Wednesday, November 10, 2010

ASP.NET GridView Subclass with Dynamic Footer Totals

A frequent requirement when using an ASP.NET GridView on a web page is to have a footer with totals for numeric columns in the GridView. Here is a GridView subclass that calculates footer totals dynamically.  It requires 3 parameters:

FirstComputedColumnIndex - the for index of the first column in the data set to be computed
FirstVisbleComputedColumnIndex - for the index of the first computed column to be shown
NumberOfComputedColumns - for the number of computed columns.

Here is the class code:

namespace Eric.TotalGrid {
  public partial class GridView : System.Web.UI.WebControls.GridView
    {
        private Indexer footerTotals;
        public int FirstComputedColumnIndex { get; set; }
        public int FirstVisbleComputedColumnIndex { get; set; }
        public int NumberOfComputedColumns { get; set; }    

        protected override void OnLoad(EventArgs e)
        {
            ShowFooter = true;
            base.OnLoad(e);
        }
        protected override void OnInit(EventArgs e)
        {
            footerTotals = new Indexer(NumberOfComputedColumns);
            InitializeComponent();
            base.OnInit(e);
        }

        private void InitializeComponent()
        {
            this.RowDataBound += new GridViewRowEventHandler(this.GridView1_RowDataBound);
        }

        protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
        {           

            DataRowView tableData = e.Row.DataItem as DataRowView;

            if (e.Row.RowType == DataControlRowType.DataRow)
            {            
                for (int i = FirstComputedColumnIndex; i < (FirstComputedColumnIndex + NumberOfComputedColumns); i++)
                {               
                    if (tableData[i] != DBNull.Value)
                    {
                        decimal result = 0;
                        if (Decimal.TryParse(tableData[i].ToString(), out result))
                        {
                            footerTotals[i - FirstComputedColumnIndex] += result;
                        }
                    }
                }
            }
            else if (e.Row.RowType == DataControlRowType.Footer)
            {
                for (int i = 0; i < NumberOfComputedColumns; i++)
                {
                    if (e.Row.Cells.Count > (i + FirstVisbleComputedColumnIndex))
                        e.Row.Cells[i + FirstVisbleComputedColumnIndex].Text = footerTotals[i].ToString();
                }
            }
        }
}



The key to this GridView is using an Indexer class that can be accessed like an array. Here is its listing:


class Indexer
        {
            private int _upperLimit;      

            private decimal[] myArray;

            public Indexer(int limit)
            {
                _upperLimit = limit;
                myArray = new decimal[_upperLimit];
            }
            public decimal this[int index]   // Indexer declaration
            {
                get
                {
                    // Check the index limits.
                    if (index < 0 || index >= _upperLimit)
                        return 0;
                    else
                        return myArray[index];
                }
                set
                {
                    if (!(index < 0 || index >= _upperLimit))
                        myArray[index] = value;
                }
            }
        }
The Indexer class can be nested within the GridView subclass.


The last example shows how to use the custom GridView on a ASP.NET web page:
First,  use the register tag:
<%@ Register Namespace="Eric.TotalGrid" TagPrefix="x" Assembly="TotalGrid" %>

Then, use it just like any other GridView:

<x:GridView runat="server" ....
FirstComputedColumnIndex="4" FirstVisbleComputedColumnIndex="3" NumberOfComputedColumns="10"  >

No comments:

Post a Comment