Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to add template columns to a DataGrid by code

Miscellaneous

How to add template columns to a DataGrid by code

by  JCruz063  Posted    (Edited  )
Introduction
As we all know, the DataGrid web server control is, by far, the most powerful of the intrinsic .NET web server controls. One of the reasons why this is the case is that the DataGrid allows the programmer to perform complex tasks such as editing, paging, among others, with miminum code. Template columns are another one of the niceties that makes the DataGrid so great. With template columns, controls could be added within the cells of the DataGrid to allow a level of flexibility that is simply to good to pass by unnoticed.

While there are tons of sources that describe how to implement template columns at design time, very few exist that talk about how template columns could be implemented at run time. Implementing template columns at run time is the topic of this FAQ.

Note: The reason why I needed to implement template columns at run time is that my application displays a grid with text boxes that allow the user to select data he is interested in. Each column in the grid would be composed of check boxes for the user to make his selections. Now, the number of columns varies depending on the user and thus I would only know at run time how many columns the grid would have. Therefore, I needed a way to simply create the template columns at run time, depending on the user that was logged on to my site.

About the ITemplate Interface...
Creating a template column at run time is very simple. The general approach is the following:
Code:
TemplateColumn tc = new TemplateColumn();
tc.HeaderText = [Text of column header];
tc.ItemTemplate = [b][ITemplate type][/b];
[color green]// dg is the DataGrid control[/color]
dg.Columns.Add(tc);

As you can see from the above code snippet, you simply create a TemplateColumn variable, give values to its Text and ItemTemplate properties and you're ready to go. The important part lies in the type of the ItemTemplate property. As you can see, this must be a class that supports the ITemplate interface. Thus, adding a template column to a grid at run time will consist of creating a class that implements the ITemplate interface. We will see how to create such a class.

Now, the ITemplate interface has only one method, InstantiateIn. This method is called when a new instance of the template column is created. It takes one parameter of type System.Web.UI.Control which represents the container control that hosts the controls within the template column. Thus, this method is where you would create the controls that you would like displayed in your template column. In my case, I needed a check box in my template column thus my class looks like this:
Code:
private class CheckBoxTemplate : ITemplate
{		
  // Implementation of ITemplate
  public void InstantiateIn(System.Web.UI.Control container)
    {	
      [color green]// Create a check box[/color]
      CheckBox cb = new CheckBox();
      [color green]// Make the check box appear 
      // in the column[/color]
      container.Controls.Add(cb);
    }
}

That's it! This is all you need to create a template column for a DataGrid at run time. As you may suspect, you can set the properties of the text box (or whatever control you create) in whatever way you like. Also, you're not limited to adding just one control, but you can add as many as you want. Now, tell me that's not cool...

Data Biding
But that's not all! The interesting stuff gets even more interesting when you add data binding to the controls you create in InstantiateIn. To implement data binding, you would have to write code to the DataBinding event of the controls you create. The event handling mechanism is the same used in Web and Windows forms: You create a method with the same signature of the delegate of the event and then add the method to the delegate. This is how the class looks now (new code is in bold).
Code:
private class CheckBoxTemplate : ITemplate
{		
  public void InstantiateIn(System.Web.UI.Control
  container)
  {
    [color green]// Create a check box[/color]
    CheckBox cb = new CheckBox();
    [color green]//Attach method to delegate[/color]
    [b]cb.DataBinding += 
    new System.EventHandler(this.BindCheckBox);[/b]
    container.Controls.Add(cb);
  }

  [color green]//Method that responds to the
  DataBinding event [/color][b]	
  private void BindCheckBox(object sender,
  System.EventArgs e)
  {
    CheckBox cb = (CheckBox)sender;
    DataGridItem container = 
    (DataGridItem)cb.NamingContainer;	
    cb.Checked = [Data binding expression];	
  } 
}[/b]

As you can see, the InstantiateIn method has one new line of code:
Code:
[b]cb.DataBinding += 
   new System.EventHandler(this.BindCheckBox);[/b]

All this does is it attaches the BindCheckBox method to the DataBinding event of the check box. The delegate of the DataBinding event has two arguments: sender, which is of type object and e, which is of type EventArgs (We really don't need e for data binding). sender represents the check box that is being bound, and that's why I have the line:

Code:
[b]CheckBox cb = (CheckBox)sender;[/b]

which simply gets a reference to such CheckBox. Now, the NamingContainer property of the check box represents the DataGridItem (in other words, the row) of the grid where the CheckBox control is. Thus with the following line, I get a reference to the row of the grid where the CheckBox is:

Code:
[b]DataGridItem container = 
(DataGridItem)cb.NamingContainer;[/b]

Finally, assuming that the DataGrid control is bound to some data source that has a field named "ItemID", we could write a data binding expression using DataBinder.Eval method. The line below (which is not in the code above) sets the Checked property of the CheckBox to true if the "ItemID" of the datasource is 10.

Code:
[b]cb.Checked = 
(DataBinder.Eval(container.DataItem, "ItemID").ToString() == "10";);[/b]

In case you don't know what the Eval method is, it's simply a method that takes in a DataGridItem (i.e. a row in the DataGrid) and a string representing a field in such row, and returns, as an object, the value for the such field in the such row.

Of course, your data binding expressions could be as complex as you want. In this method, you could literally do anything...

Finally, the line which is missing for the very first code snipped shown here is the following (in bold):
Code:
TemplateColumn tc = new TemplateColumn();
tc.HeaderText = [Text of column header];
[color green]//Isn't this beautiful? [/color]
[b]tc.ItemTemplate = new CheckBoxTemplate();[/b]
[color green]// dg is the DataGrid control[/color]
dg.Columns.Add(tc);

Cool, eh?

Conclusion
You may may want to keep the follow two points in mind:
1 - The class that implements the ITemplate interface is very simple and maybe implemented as a private class within the page where it will be used. However, this doesn't have to be so. You may add complexity to this class by using overloaded constructors that may set initial settins to set the appearance of the controls in the template columns.

2 - You should call the DataGrid's DataBind method after you have added the template columns. If you do it before, you won't see the template columns.

That's all folks! If you read this FAQ and have problems understanding it, you may write me at cuchy063@hotmail.com

JC
Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top