Extending GridView to access generated columns

ASP.NET’s GridView is a useful control and one of it’s best features is it’s ability to generate the columns automatically from the data source given.

The problem however is that these generated columns are not exposed as part of the Columns collection or indeed available at all so you can’t hide or manipulate the selected columns.

One simple scenario might be that you want the first column to be a “View” link to drill down into the row displayed. Whilst you can add the column to the GridView before data binding you can’t actually pull out the information needed from another columns to construct the URL.

By sub-classing GridView you can obtain this functionality with some caveats.

Version 1: Auto generated columns added to the Columns collection… with caveats.

using System;
using System.Data;
using System.Collections;
using System.Web.UI.WebControls;

public class GridViewEx1 : GridView
{
    private DataControlFieldCollection originalColumns;

    public GridViewEx1() : base() {
    }

    public void RecordColumns() {
        originalColumns = new DataControlFieldCollection();
        foreach(DataControlField column in Columns)
            originalColumns.Add(column as DataControlField);
    }

    public void ResetColumns() {
        if (originalColumns == null)
            RecordColumns();
        else {
            Columns.Clear();
            foreach(DataControlField column in originalColumns)
                Columns.Add(column as DataControlField);
        }
    }

    protected override ICollection CreateColumns(PagedDataSource dataSource, bool useDataSource) {
        ResetColumns();
        ICollection generatedColumns = base.CreateColumns(dataSource, useDataSource);
        foreach(DataControlField column in generatedColumns)
            if (!originalColumns.Contains(column))
                Columns.Add(column as DataControlField);
        return Columns;
    }
}

This version provides some compatibility with existing code/expectations in that the auto-generated columns are part of the Columns collection after the DataBind.

Should you call DataBind again however as well as wiping out the changes to the generated columns (they are, after all re-generated) any additional columns added to the collection after the first DataBind will also be lost as it does not track which are added by the programmer and which automatically.

Version 2: All bound columns exposed as BoundColumns, user ones as Columns.

using System;
using System.Data;
using System.Collections;
using System.Web.UI.WebControls;

public class GridViewEx2 : GridView
{
    private DataControlFieldCollection boundColumns = new DataControlFieldCollection();

    public GridViewEx2() : base() {
    }

    public DataControlFieldCollection BoundColumns {
        get { return boundColumns; }
    }

    protected override ICollection CreateColumns(PagedDataSource dataSource, bool useDataSource) {
        ICollection generatedColumns = base.CreateColumns(dataSource, useDataSource);
        BoundColumns.Clear();
        foreach (DataControlField column in generatedColumns)
            BoundColumns.Add(column as DataControlField);
        return BoundColumns;
    }
}

After the DataBind you will have full access to the generated columns as part of the BoundColumns collection.

[)amien

0 responses