2011/09/30

Customizing DataGrid ItemTemplate using ITemplate.InstantiateIn in ASP.NET

I would like to talk in this post about customizing the ItemTemplate in ASP.NET DataGrid. Let's say you have a situation where you want to have a different control in each row in the DataGrid column; for example, the first row you have a textbox in the column, the second row you have a datetime picker in the same column, etc.

The standard implementation of the ItemTemplate in the DataGrid allows you to add one or more controls in each column, and these same controls will be repeated in every row in the grid.

To customize this behavior you have to do the following:
- Create your custom ItemTemplate class, this class should implement the method InstantiateIn in the ITemplate interface.
- Render the controls in each row as required by your implementation in the grid.
The following shows the implementation of this approach:




public class MyCustomItemTemplate : ITemplate
    {
        public Type dataType { get; set; }
        public ListItemType listItemType { get; set; }
        public string columnName { get; set; }
 
        void ITemplate.InstantiateIn(System.Web.UI.Control container)
        {
            switch (listItemType)
            {
                case ListItemType.Header:
                    Label lbl = new Label();
                    lbl.Text = columnName;
                    container.Controls.Add(lbl);
                    break;
                case ListItemType.Item:
                    if (dataType.Equals(typeof(bool)))
                    {
                        CheckBox chk1 = new CheckBox();
                        //chk1.DataBinding += new EventHandler(chk1_DataBinding); // Implement this method to handle your custom binding
                        container.Controls.Add(chk1);
                    }
                    else if (dataType.Equals(typeof(string)))
                    {
                        TextBox txt1 = new TextBox();
                        //txt1.DataBinding += new EventHandler(txt1_DataBinding); // Implement this method to handle your custom binding
                        container.Controls.Add(txt1);
                    }
                    break;
                // Add other data types here and their controls
            }
        }
    }

Now that we have prepared our ItemTemplate implementation, we need to set it inside the grid after the row is created and override the default ItemTemplate rendering; by handling the RowCreated event and calling the InstantiateIn method as follows:


public void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
        {
            if (e.Row.RowType == DataControlRowType.DataRow)
            {               
                // For this example - Odd rows have texboxes and Even ones have checkboxes
                if (e.Row.RowIndex % 2 == 1)
                {
                    GridView gv = (GridView)sender;
                    ITemplate v = ((ITemplate)(((TemplateField)(((DataControlFieldCell)(e.Row.Cells[0])).ContainingField)).ItemTemplate));
                    v = new MyCustomItemTemplate();
                    (v as MyCustomItemTemplate).dataType = typeof(string);
                    (v as MyCustomItemTemplate).columnName = "Item";
                    (v as MyCustomItemTemplate).listItemType = ListItemType.Item;
                    if (((DataControlFieldCell)(e.Row.Cells[0])).Controls.Count > 0)
                    {
                        // This line is to remove default bound controls by the original ItemTemplate (in this case Label control)
                        ((DataControlFieldCell)(e.Row.Cells[0])).Controls.Clear(); // Remove(((DataControlFieldCell)e.Row.Cells[0]).Controls[0]);
                    }
                    v.InstantiateIn((DataControlFieldCell)(e.Row.Cells[0]));
                }
                else
                {
                    GridView gv = (GridView)sender;
                    ITemplate v = ((ITemplate)(((TemplateField)(((DataControlFieldCell)(e.Row.Cells[0])).ContainingField)).ItemTemplate));
                    v = new MyCustomItemTemplate();
                    (v as MyCustomItemTemplate).dataType = typeof(bool);
                    (v as MyCustomItemTemplate).columnName = "Item";
                    (v as MyCustomItemTemplate).listItemType = ListItemType.Item;
                    if (((DataControlFieldCell)(e.Row.Cells[0])).Controls.Count > 0)
                    {
                        // This line is to remove default bound controls by the original ItemTemplate (in this case Label control)
                        ((DataControlFieldCell)(e.Row.Cells[0])).Controls.Clear(); //Remove(((DataControlFieldCell)e.Row.Cells[0]).Controls[0]);
                    }
                    v.InstantiateIn((DataControlFieldCell)(e.Row.Cells[0]));
                }
            }
        }
    }

Of course, in the aspx page you would have something like this:


 <asp:GridView ID="GridView1" runat="server" OnRowCreated="GridView1_RowCreated" AutoGenerateColumns="false">
        <Columns>            
            <asp:TemplateField HeaderText="Custom Item Template">
                <ItemTemplate>
                    <asp:Label ID="lblDesc" Text='<%# Bind("Desc") %>' runat="server"></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>

With this implementation, we have a datagrid that renders different controls for each row according to our requirements.

No comments:

Post a Comment