Monday, May 10, 2010

Sum total line in footer of ASP.Net gridview

A few years ago, I was looking for a solution to sum up a column of numbers in a gridview in ASP.Net and display the total in the footer of the gridview.  I found a solution on aspalliance that worked well for me for these few years.  It uses TemplateFields to call one function in the ItemTemplate that adds the values and another function in the FooterTemplate that displays the total.  I enhanced it to use a Hashtable so that when I had lots of fields I wanted to total, I didn't have to make a separate variable for each one.  I just added a new key to the Hashtable.

But today I wanted to try to find a solution that was less work, where I could still use BoundFields.  I found a good solution on Microsoft.com using the RowDataBound event.  With this solution, you can still use BoundFields, but you have to add code to the function for each column that you want to sum up.  I have a grid with over 60 columns (because we hide and show different ones for different scenarios) so I was really hoping to  find some way where I didn't have to write code for each field.

So the solution I came up with is below, in C#.  It's very similar to the Microsoft.com solution, but with a couple modifications.  First, I'm using Hashtables again, two this time: one for the totals and one for the type of the field -- integer or currency.  Second is the automatic check for whether a field is numeric or not, and if its is, what kind of number -- integer or currency.  I check this simply by looking for the dollar sign in the text of the cell.  Note that when parsing the text to number format, the System.Globalization.NumberStyles.Any parameter is very important because it handles characters like the $ and parentheses for negative numbers in accounting format.

One drawback of this method is that it will total every numeric field, including zip codes, for example.  But it could be easily modified to either list specific columns to total or specific columns to exclude.  One other drawback is that it doesn't work for percentage columns.  You can't total up different percentage values anyway to get a percentage that is accurate for the total line, but at least with a TemplateField solution, you can divide the appropriate totals to get the correct percentage in the FooterTemplate.

Listing, in C#:


    Hashtable total = new Hashtable();
    Hashtable fieldType = new Hashtable();


    protected void reportGrid_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        int i;
        double result;
        string cellText;

        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            for (i = 0; i < e.Row.Cells.Count; i++)
            {
                cellText = e.Row.Cells[i].Text;

                try
                {
                    result = Double.Parse(cellText, System.Globalization.NumberStyles.Any);

                    // if this didn't go to the catch, then field was a number
                    // if it has a $ in it, save in Hashtable that it is currency field

                    // this code assumes that the field won't change type from row to row

                    if (cellText.Contains("$"))
                    {
                        fieldType[i] = "C";
                    }
                    else
                    {
                        fieldType[i] = "N0";
                    }

                    if (total.ContainsKey(i))
                    {
                        total[i] = double.Parse(total[i].ToString()) + result;
                    }
                    else
                    {
                        total[i] = result;
                    }
                }
                catch
                {
                    // do nothing
                }
            }
        }
        else if (e.Row.RowType == DataControlRowType.Footer)
        {
            for (i = 0; i < e.Row.Cells.Count; i++)
            {
                // display the value of any Hashtable total field that has a key
                if (total.ContainsKey(i))
                {
                    e.Row.Cells[i].Text = String.Format("{0:" + fieldType[i].ToString() + "}", total[i]);
                }
            }
        }
    }

0 comments:

Post a Comment