Building a Full-Featured Custom DataGrid Control

DataGrid Enhancements

The final section below is compiled from forum questions that were posted to me and that I answered on DNJ. I also include additional code to further enhance the Datagrid's functionality in this article.

The four added topics are:

  1. How to customize the Datagrid pager
  2. Adding a Custom Datagrid ItemTemplate
  3. Formatting Column Output in the DataGrid
  4. Adding an Incremental Count Column To DataGrid

How to customize the Datagrid pager


For example, to get your Datagrid pager to display paging like "<Prev 12 13 14 15 Next>", you'll need to replace the start and end paging ellipses "..." with < Prev and Next >. How's that done? By enumerating through the paging link button controls, determine the index position for the ellipses and then replacing them.

Here's how:

Here is the entire GridCreated method. Replace the original one found in the article, with the following:

private void GridCreated (Object sender, DataGridItemEventArgs e)
{

    //Declare the ItemType
    ListItemType elemType = e.Item.ItemType;
    if (elemType == ListItemType.Item || elemType == ListItemType.AlternatingItem)
    {
        //A DataGrid Item represents an item (row) in the DataGrid control
        //e.Item is the table row where the command is raised
        DataGridItem dgRow = (DataGridItem) e.Item;
        int rowCntIncr = dgRow.DataSetIndex + 1; //Gets the index number of the DataGridItem object from the bound data source
        //Get the start and end index count from DataGrid
        //declare as typed variables first then convert
        StartCnt = rowCntIncr-dgRow.ItemIndex;
        EndCnt = rowCntIncr;
    }
    else if (elemType == ListItemType.Pager)
    {
        TableCell Pager = (TableCell) e.Item.Controls[0];
        //Additional Pager Text
        TableCell dgPagerText = new TableCell();

        dgPagerText.Width = Unit.Percentage(25);
        dgPagerText.ID = "dgPagerText";
        dgPagerText.HorizontalAlign = HorizontalAlign.Left;
        Label InfoText = new Label();
        InfoText.ID = "InfoText";
        dgPagerText.Controls.Add(InfoText);
        //Add Table Cell to Pager
        e.Item.Controls.AddAt(0, dgPagerText);

        //Add custom Previous/Next paging section
        //Loop indexed by 2 through datagrid paging numbers controls jumping over the spaces
        for (int i = 0; i <= Pager.Controls.Count; i+=2)
        {
            object pgNumbers = Pager.Controls[i];
            int bCnt = PagerStyle.PageButtonCount;
            int endPagingIndex = Pager.Controls.Count-1;
            if (pgNumbers.GetType().Name == "DataGridLinkButton")
            {
                LinkButton lb = (LinkButton) pgNumbers;
                //Deal only with ellipses
                if (lb.Text == "...")
                {
                    //Find index position of paging ellipses
                    if (i == 0)
                    {
                        lb.Text = "< Prev";
                    }
                    else if (i == endPagingIndex)
                    {
                        lb.Text = "Next >";
                    }
                }
            }
        }//End Loop
    }
}



Formatting Column Output in the DataGrid

To begin, you'll first want to disable AutoGenerateColumns by setting it to false, by doing so set your query to "Select * From ..." etc. Next, the following code would go into the classes GetDataGrid() method, right before the DataSource = GridCachedData(); line.

The code below creates custom BoundColumns that permit formatting. In this example we formatted our SupplierID as currency just to show how it's done, as in your question:

//Programmatic Custom BoundColumns
BoundColumn SupplierID = new BoundColumn();
BoundColumn CompanyName = new BoundColumn();
BoundColumn ContactName = new BoundColumn();
BoundColumn Country = new BoundColumn();
SupplierID.HeaderText="No.";
SupplierID.DataField="SupplierID";
SupplierID.DataFormatString = "{0:c}";
CompanyName.HeaderText="CompanyName";
CompanyName.DataField="CompanyName";
ContactName.HeaderText="ContactName";
ContactName.DataField="ContactName";
Country.HeaderText="Country";
Country.DataField="Country";

//Clear the DataGrid first
Columns.Clear();
//Add them to our Datagrid
Columns.Add(SupplierID);
Columns.Add(CompanyName);
Columns.Add(ContactName);
Columns.Add(Country);

Adding a Custom Datagrid ItemTemplate

I'll also demonstrate a couple of ways to programmatically add a custom ItemTemplate to your datagrid.

Normally, to get an ItemTemplate with your Datagrid, you'd do something like this:

<asp:TemplateColumn>
    <HeaderTemplate>Country</HeaderTemplate>
    <ItemTemplate>
        <asp:Label Text='<%# DataBinder.Eval(Container.DataItem, "Country") %>'
runat="server"/>
    </ItemTemplate>
</asp:TemplateColumn>

To do the same thing in our custom Datagrid control is easy. Here now we'll modify the "Country" datafield column in this case, programmatically.

Setting up an ItemTemplate is easy, as shown before in our BoundColumn thread, like so:

TemplateColumn Temp = new TemplateColumn();

Next, you add whatever TemplateColumn class members you wish. In this case, we'll add a header text:

Temp.HeaderText= "Country";

and then add it to your datagrid as in our previous DG formatting thread, in any order:

Columns.Add (Temp);

Now this works fine, except you won't get any data. Here are two ways to get data.

Method one is a quick and easy. To get something from this you can load an external server control:

Temp.ItemTemplate = Page.LoadTemplate("control.ascx");

This of course could contain pretty much whatever, within reason of course. The other method in getting data into your custom ItemTemplate is by implementing ITemplate. The class to do this is:

public class custDGTemplate : ITemplate
{
    private string fieldname;
    public custDGTemplate (string itemcolumname)
    {
        fieldname = itemcolumname;
    }
    public void InstantiateIn (Control container)
    {
        LiteralControl lc = new LiteralControl();
        lc.DataBinding += new EventHandler(this.OnDataBinding);
        container.Controls.Add (lc);
    }
    public void OnDataBinding (object sender, EventArgs e)
    {
        LiteralControl lc = (LiteralControl) sender;
        DataGridItem container = (DataGridItem) lc.NamingContainer;
        lc.Text = ((DataRowView) container.DataItem) [fieldname].ToString();
    }
}

Add this class anywhere within the mycustDG.cs source code file. Next, add the line below to your other custom ItemTemplate's members and pass the database field name to the to your custDGTemplate class, like so:

Temp.ItemTemplate = new custDGTemplate ("Country");

Adding an Incremental Count Column To DataGrid

I've got a cool little code snippet that you can add to the Datagrid to give it an new column with an incremental count. This first newly added column will have the count, with row 1 being 1, row 2 being 2, and the count goes on.

It's the same principle laid out in my myCustDG.cs class file's GridCreated method. So to implement this, you'll need to do two things:

1) In accordance to the previous two forum threads I added on creating custom templates, follow those examples and programmatically add another BoundColumn to the DataGrid so it can accommodate the incremental counting, like so:

BoundColumn Count = new BoundColumn();

Then add the header text:

Count.HeaderText = "No.";

Then add it to the DataGrid with the rest, just like in the other forum threads:

Columns.Add(Count);

2) Since we're already getting a count of how many records are found in our GridCreated method by showing us in our results – Results No. x to x, and now that we have just created a new column, all we need to do is write this number value to that column, by adding the two lines below to the GridCreated method, within the ListItemType.Item / ListItemType.AlternatingItem conditional after EndCnt = rowCntIncr; and before the ListItemType.Pager check:

//Add new Literal Control to write our Incremental Count from rowCntIncr
LiteralControl numberIncr = new LiteralControl(rowCntIncr.ToString());
//Write out to the first column the value count
dgRow.Cells[0].Controls.Add (numberIncr);

That's it, a quick and easy way to get an incremental count for your DataGrid.

You might also like...

Comments

About the author

Dimitrios Markatos

Dimitrios Markatos United States

Dimitrios, or Jimmy as his friends call him, is a .NET developer/architect who specializes in Microsoft Technologies for creating high-performance and scalable data-driven enterprise Web and des...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“The greatest performance improvement of all is when a system goes from not-working to working.” - John Ousterhout