Saturday, November 17, 2007

AggregateBoundField for GridView

I've been working on a reusable solution for adding aggregate totals to a GridView. One issue that I want to address is using page level variables to calculate totals. The second issue I would like to address is using column indexes to place the toals in the footer.

Here is the solution I have often seen for adding totals to a report:


int _iTotal = 0;

void gvReport_RowDataBound(object sender, GridViewRowEventArgs e) {

    if (e.Row.RowType == DataControlRowType.DataRow) {

        DataRow dr = ((DataRowView)e.Row.DataItem).Row;

        _iTotal += Convert.ToInt32(dr["count"]);

    }

    if (e.Row.RowType == DataControlRowType.Footer) {

        e.Row.Cells[0].Text = _iTotal.ToString();

    }

}

The problems I see here are:
a) _iTotal can be modified outside the scope of gvReport_RowDataBound but is only relevant within said scope.
b) If a cell is added in front of this column, we need to go back in and ajust our indexes because it has no logical link to the column. We could improve this slightly by using an enum to store the column indexes but the maintenance issue still remails.
c) Each column needs to implement the same logic to calculate totals.

For issue a) I suggest that it is possible to use the DataTable.Compute() method to easily obtain totals and averages.


e.Row.Cells[0].Text = _dt.Compute("SUM(count)");

For issue b) I believe that the aggregate function needs to be declared within the column. For my solution, I have implemented an AggregateBoundField that inherits from the BoundField control.


public class AggregateBoundField : BoundField {
    private AggregateType _eAggregateFunction;
 
    [Description("The function to use in DataTable.Compute()"),
    Category("Behavior"),
    DefaultValue(typeof(AggregateType), "SUM")]
    public AggregateType AggregateFunction {
        set { _eAggregateFunction = value; }
        get { return _eAggregateFunction; }
    }
}


For issue c) I have written a function that will itterate through all the AggregateBoundField controls in the GridView to assign the footer text.




private static void SetFooter(GridView grid, DataTable dataSource){
    string sExpressionFunction;
    object oComputedValue;
    AggregateBoundField af;

    foreach (DataControlField fcf in grid.Columns) {
        if (fcf is AggregateBoundField) {
            af = (AggregateBoundField)fcf;
            if (af.DataField.Length != 0) {
                sExpressionFunction = string.Format("{0}({1})", Enum.GetName(typeof(AggregateType), af.AggregateFunction), af.DataField);
                oComputedValue = dataSource.Compute(sExpressionFunction, "");
 
                if (af.DataFormatString.Length != 0) {
                    af.FooterText = string.Format(af.DataFormatString, oComputedValue);
                }
                else {
                    af.FooterText = oComputedValue.ToString();
                }
            }
        }
    }
}

Saturday, October 20, 2007

Printing in .Net - Class Design

I've been tasked with printing some reports in a windows application at work. There seems to be a lot of extra work associated with printing such as maintaining fonts, brushes, pagination, and wordwrap. Thus I decided to start with a printer helper class to keep track of pages, a style class to hold the Brush and Font, and another class to print to the Graphics object.

I first implemented the helper class as the PrintHelper has a PrintDocument; I've began to refactor my design and I'm now thinking that there should be a class that inherits from the PrintDocument instead.

I'll update as my design progresses.

Friday, October 12, 2007

fxCop

After a weekly meeting in which we decerned to enforce our coding standards more rigorously I remembered looking into fxCop a while back. It looks pretty flexible and should be an easy way to check conformance to our coding standards.

The included rules that ship with fxCop are extensive but some don't apply to our environment or conflict with our existing standards. I'm going to try to run fxCop on all my new developement for now and narrow down what needs to be excluded. If we could write some custom rules that conform to our coding standards they would be especially beneficial durring code review processes and for new developers.

Wednesday, July 11, 2007

Click Once Deployment

With "Click Once Deployment" deploying a client application couldn't be easier. A simple setup that is deployed from a website is created automatically for you. You can also attach dependencies such as the .Net Framework. Updates can also be published and the client will automatically update to the latest version on the server.

One major issue that I ran into is that "click once" currently only works in Internet Explorer. I was upset that they would exclude such a major feature. This is a crippling issue for external applications and even a glaring issue for internal applications (with IE only environments).

Despite it's current drawbacks, it is exciting to see the power that they have built into .NET 2.0.

Friday, June 29, 2007

T-SQL bitwise not

Today I stumbled upon a feature in T-Sql that I haven't found before. I was looking for a way to do a bitwise not. I've seen this done with a case statement in a couple of places however it's clumsy and verbose:

CASE WHEN my_bit_f = 1 THEN 0 ELSE 1 END

Instead this can be simplified to:

~my_bit_f


MSDN:
http://msdn2.microsoft.com/en-us/library/ms173468.aspx