14 July 2006

GridView’s header and empty DataSource

The successor of DataGrid in ASP.NET 2.0 – GridView behaves unusually sometimes. For example if binded ObjectDataSource is empty, then GridView’s header is not rendered. This is not the required behavior in most of the cases. If you want to show the header of the GridView when binded data source is empty, there are several solutions, but I will describe the one I like most.

Solution in brief: Subclass GridView control, override CreateChildControls method and manualy create header if binded DataSource is empty. The implementation of CreateChildControls method may look like:



protected override int CreateChildControls(IEnumerable dataSource,
    bool dataBinding)
{
    int numRows = base.CreateChildControls(dataSource, dataBinding);
 
    if (numRows == 0)
    {
        Table table = new Table();
        table.ID = this.ID;
 
        GridViewRow row = base.CreateRow(-1, -1,
                DataControlRowType.Header, DataControlRowState.Normal);
 
        DataControlField[] fields = new
                DataControlField[this.Columns.Count];
        this.Columns.CopyTo(fields, 0);
        this.InitializeRow(row, fields);
        table.Rows.Add(row);
        this.Controls.Add(table);
    }
 
    return numRows;
}


The code above adds only a header to the grid. If you need you can add another empty row, where appropriate message may be shown.

Adding footer is a little bit tricky. GridView exposes a public property for managing the footer. So the footer added by you, must be accessible via this property. The solution to the problem is to override the virtual property FooterRow (To Microsoft ASP.NET 2 Team: Thank you for making this property virtual. Unfortunately some methods in ASP.NET 2 are not virtual and extending the framework sometimes is not so easy). According to the explanations above the implementation may look like:



private GridViewRow mFooterRow = null;
 
public override GridViewRow FooterRow
{
    get
    {
        if (mFooterRow != null)
        {
            return mFooterRow;
        }
        else
        {
            return base.FooterRow;
        }
    }
}
 
protected override int CreateChildControls(IEnumerable dataSource,
    bool dataBinding)
{
    this.mFooterRow = null;
 
    int numRows = base.CreateChildControls(dataSource, dataBinding);
 
    if (numRows == 0)
    {
        Table table = new Table();
        table.ID = this.ID;
 
        GridViewRow row = base.CreateRow(-1, -1,
            DataControlRowType.Header, DataControlRowState.Normal);
 
        DataControlField[] fields = new
            DataControlField[this.Columns.Count];
        this.Columns.CopyTo(fields, 0);
        this.InitializeRow(row, fields);
        table.Rows.Add(row);
 
        this.mFooterRow = base.CreateRow(-1, -1,
            DataControlRowType.Footer, DataControlRowState.Normal);
        fields = new DataControlField[this.Columns.Count];
        this.Columns.CopyTo(fields, 0);
        this.InitializeRow(mFooterRow, fields);
        table.Rows.Add(mFooterRow);
        this.Controls.Add(table);
    }
 
    return numRows;
}

During the creation of the component I remembered the old Delphi days. Creating new .NET control is almost as easy and funny as it was in Delphi.

No comments: