© 2004 Microsoft Corporation. All rights reserved.

Figure 1 DataGrid Column Templates

Name
Description
ItemTemplate
Contains the template for the items in a DataGrid's column.
<ItemTemplate>
  <asp:label runat="server" text= '<%# ... %>'...>
</ItemTemplate>
You can use any combination of HTML text and ASP.NET controls to populate the column.
EditItemTemplate
Controls the contents of the item selected for editing in the column of the DataGrid control. Place the controls you need for editing the cell between the opening and closing EditItemTemplate tags.
<EditItemTemplate>
  <asp:textbox runat="server" text= '<%# ... %>'...>
</EditItemTemplate>
HeaderTemplate
Contains the template for the heading section.
<HeaderTemplate>
  <asp:label runat="server" text= "Header"...>
</HeaderTemplate>
If you omit this template, the column header is rendered with a label or a hyperlink if sorting is enabled. By specifying a custom template, you make yourself responsible to provide the user interface needed to enable sorting on the column.
FooterTemplate
Contains the template for the footer section of the column. The default value is a null reference.
<FooterTemplate>
  <asp:label runat="server" text= "..."...>
</FooterTemplate>
The footer is displayed only if the ShowFooter property of the DataGrid is set to True.
Figure 3 Adding the Sort Dropdown
public void ItemCreated(Object sender, DataGridItemEventArgs e)
{
    ListItemType lit = e.Item.ItemType;
    if (lit == ListItemType.Header)
    {
        // Create and fill a dropdown list control
        DropDownList dd = new DropDownList();
        dd.ID = "ddSort";
        ListItem li1, li2, li3;

        // ListItem constructor takes Text and Value for the item
        li1 = new ListItem("Title of courtesy", "titleofcourtesy");
        dd.Items.Add(li1);

        li2 = new ListItem("Last Name", "lastname");
        dd.Items.Add(li2);

        li3 = new ListItem("First Name", "firstname");
        dd.Items.Add(li3);

        // Selects the item, if any, that was selected last time
        dd.SelectedIndex = Convert.ToInt32(grid.Attributes["FieldIndex"]);

        // Add the dropdown list to the header of the 2nd column
        TableCell cell = (TableCell) e.Item.Controls[1];
        cell.Controls.Add(dd);
    }
}

public void SortCommand(Object sender, DataGridSortCommandEventArgs e)
{
    // Code that retrieves the grid's data source GOES HERE
    •••

    // Sort by the specified expression or figure it out 
    if (e.SortExpression != "*")
        dv.Sort = e.SortExpression;
    else
    {
        // Retrieves the dropdown list control through its ID 
        DataGridItem dgi = (DataGridItem) e.CommandSource;
        DropDownList dd = (DropDownList) dgi.FindControl("ddSort");

        // Retrieves the sorting expression from the list
        dv.Sort = dd.SelectedItem.Value; 

        // Persists the currently selected dropdown item
        grid.Attributes["FieldIndex"] = dd.SelectedIndex.ToString();
    }
    
    // Refreshes the grid
    grid.DataBind();
}
Figure 7 Intercepting Cell Creation Event
// ItemDataBound is an event that occurs when an item is 
// data-bound to the DataGrid control. Similar events fire
// for other iterative controls like the DataList control 
// and the Repeater control.

public void ItemDataBound(Object sender, DataGridItemEventArgs e)
{
    // Get the data item and make sure it is a non-null object
    DataRowView drv = (DataRowView) e.Item.DataItem;
    if (drv == null)
        return;

    // Access the contents of the column of interest. If the
    // value found is greater than 0 then use the webding 
    // character that evaluates to a checkmark
 
    if (((int) drv["boss"]) >0)
    {
        e.Item.Cells[3].Font.Name = "Webdings";
        e.Item.Cells[3].Text = "a";  
    }
    else
        e.Item.Cells[3].Text = "";
}
Figure 9 Two Templates
<asp:DataGrid id="grid" runat="server"  
    AutoGenerateColumns="false"
    CssClass="Shadow" BackColor="white"
    CellPadding="2" CellSpacing="0" 
    BorderStyle="solid" BorderColor="black" BorderWidth="1"
    font-size="x-small" font-names="verdana"
    AllowPaging="true"
    PageSize="4"
    DataKeyField="employeeid"
    OnPageIndexChanged="PageIndexChanged">

<AlternatingItemStyle BackColor="palegoldenrod" />
<ItemStyle BackColor="beige" VerticalAlign="top" />
<EditItemStyle BackColor="yellow" Font-Bold="true" />
<PagerStyle Mode="NumericPages" />
<HeaderStyle ForeColor="white" BackColor="brown" HorizontalAlign="center" 
    Font-Bold="true" />

    <columns>

   <asp:BoundColumn runat="server" DataField="employeeid" 
                    HeaderText="ID">    
    <itemstyle backcolor="lightblue" font-bold="true" 
               HorizontalAlign="right" />
   </asp:BoundColumn>

   <asp:TemplateColumn runat="server" HeaderText="Employee Name">        
    <itemtemplate>
        <asp:label runat="server" 
            Text='<%# DataBinder.Eval(Container.DataItem, 
            "TitleOfCourtesy") + "<b> " + 
            DataBinder.Eval(Container.DataItem, "LastName") + 
            "</b>" + ", " + 
            DataBinder.Eval(Container.DataItem, "FirstName") %>' />            
    </itemtemplate>
   </asp:TemplateColumn>

       <asp:TemplateColumn runat="server" HeaderText="Photo">
    <itemtemplate>
        <img runat="server" width="50"  
           visible='<%# IsImageAvailable(DataBinder.Eval
           (Container.DataItem, "lastname")
           ToString()) %>'    
           src='<%# "images\\" + DataBinder.Eval(Container.DataItem, 
           "lastname") + ".bmp" %>' />
        <asp:label runat="server" text="<i><small>No picture available.
                   </small></i>" 
           visible='<%# !IsImageAvailable(DataBinder.Eval
           (Container.DataItem, 
           "lastname").ToString()) %>' />
    </itemtemplate>
       </asp:TemplateColumn>

</columns>
</asp:DataGrid>
Figure 11 In-memory Templated Column
// Used to add a dynamically created template column

public void AddTemplateColumnFromITemplate(String strHeader)
{
    TemplateColumn bc = new TemplateColumn();
    bc.HeaderText = strHeader;
    bc.ItemTemplate = new LastFirstNameTemplate();
    grid.Columns.Add(bc);
}

// This class represents a custom template. You build a template by 
// populating the container's Controls collection with new instances
// of ASP.NET server controls. If the controls are data-bound, also 
// register your own handler for the OnDataBinding event.

public class LastFirstNameTemplate : ITemplate
{

    // Instantiate the elements of the template in the given
    // container. In this case, a DataGridItem element.

    public void InstantiateIn(Control container) 
    {
        container.Controls.Add(new LiteralControl("<b>"));

        Label lblLastName = new Label();
        lblLastName.DataBinding += new EventHandler(this.BindLastName);
        container.Controls.Add(lblLastName);

        container.Controls.Add(new LiteralControl("</b>, "));

        Label lblFirstName = new Label();
        lblFirstName.DataBinding += new EventHandler(this.BindFirstName);
        container.Controls.Add(lblFirstName);
    }

    // Handler of the OnDataBinding event for the Label element
    // that renders the lastname column in the template.

    private void BindLastName(Object sender, EventArgs e)
    {
            Label l = (Label) sender;
            DataGridItem container = (DataGridItem) l.NamingContainer;
            l.Text = ((DataRowView)container.DataItem)
                ["lastname"].ToString();
    }

    // Handler of the OnDataBinding event for the Label element
    // that renders the firstname column in the template.

    private void BindFirstName(Object sender, EventArgs e)
    {
            Label l = (Label) sender;
            DataGridItem container = (DataGridItem) l.NamingContainer;
            l.Text = ((DataRowView)container.DataItem)
                ["firstname"].ToString();
    }
}
Figure 12 Methods and Properties

Property/Method
Description
AllowMultiSelect
Boolean property that enables or disables the multi-selection feature. Defaults to False
AllowMultiSelectFooter
Boolean property that enables or disables the tailor-made footer for the grid. Defaults to False. If enabled, it overrides the default footer. If disabled but the grid has a footer anyway, then the contents of this special footer are displayed as the footer of the checkbox column
SelectedItems
Read-only property that returns an array with the DataGridItem objects currently selected
ClearSelection
Method that clears all the currently selected items
Figure 14 The Control's Code
namespace BWSLib
{
    public class MultiGrid : DataGrid
    {
        // Constructor that sets some styles and graphical properties    
        public MultiGrid()
        {
            AllowMultiSelect = false;
            AllowMultiSelectFooter = false;

            // Set event handlers
            Init += new EventHandler(OnInit);
            ItemCreated += new DataGridItemEventHandler(OnItemCreated);
        }

        // PROPERTY: SelectedItems
        public ArrayList SelectedItems 
        {
            get 
            {
                if (!AllowMultiSelect)    return null;

                ArrayList a = new ArrayList();
                foreach(DataGridItem dgi in Items)
                {
                    CheckBox cb = (CheckBox) dgi.Cells[0].Controls[0];
                    if (cb.Checked)
                        a.Add(dgi);
                }
                return a;
            }
        }

        // PROPERTY: AllowMultiSelect 
        public bool AllowMultiSelect = false;

        // PROPERTY: AllowMultiSelectFooter 
        public bool AllowMultiSelectFooter = false;

        // METHOD: ClearSelection
        public void ClearSelection()
        {
            foreach(DataGridItem dgi in Items)
            {
                CheckBox cb = (CheckBox) dgi.Cells[0].Controls[0];
                cb.Checked = false;
            }
        }

        ///////////////////////////////////////////////////////////////////
        // Event Handlers        // EVENT HANDLER: Init            
        private void OnInit(Object sender, EventArgs e)
        {
            // Add a templated column that would allow for selection.
            // The item template contains a checkbox. It also features a 
            // templated footer containing links for Unselect/Select all 
            if (AllowMultiSelect)
                AddSelectColumn();
        }

        // EVENT HANDLER: Deselect
        private void OnDeselect(Object sender, EventArgs e)
        {
            ClearSelection();
        }

        // EVENT HANDLER: ItemCreated            
        private void OnItemCreated(Object sender, DataGridItemEventArgs e)
        {
            // Get the newly created item
            ListItemType itemType = e.Item.ItemType;

            ///////////////////////////////////////////////////////////////
            // FOOTER
            if (itemType == ListItemType.Footer && AllowMultiSelectFooter 
                && AllowMultiSelect)
            {
                // Look for a link button called "lnkSelect" in the context 
                // of the grid item that represents the footer
                LinkButton lb = (LinkButton) 
                    e.Item.FindControl("lnkDeselect");

                // Now you hold the living instance of the link 
                // button in the footer and can bind it to any code in the 
                // context of the MultiGrid control
                lb.Click += new EventHandler(OnDeselect);
                
                // Force ShowFooter to true
                ShowFooter = true;

                // Removes all the cells but the first 
                TableCell cell = e.Item.Cells[0];
                for (int i=1; i<Columns.Count; i++)
                {
                    e.Item.Cells.RemoveAt(1);
                }
                cell.ColumnSpan = Columns.Count;
            }
        }

        ///////////////////////////////////////////////////////////////////
        // Helper Functions

        private void AddSelectColumn()
        {
            // Create the new templated column
            TemplateColumn tc = new TemplateColumn();
            tc.ItemStyle.BackColor = Color.SkyBlue;
            tc.ItemTemplate = new SelectColumnTemplate();
            tc.FooterTemplate = new SelectFooterTemplate();
            Columns.AddAt(0, tc);
        }
    }

    ///////////////////////////////////////////////////////////////////////
    // Template Classes

    public class SelectColumnTemplate : ITemplate
    {
        public void InstantiateIn(Control container)
        {
            CheckBox cb = new CheckBox();
            container.Controls.Add(cb);
        }
    }

    public class SelectFooterTemplate : ITemplate
    {
        public void InstantiateIn(Control container)
        {
            LinkButton lb = new LinkButton();
            lb.Text = "Deselect all";
            lb.ID = "lnkDeselect";
            container.Controls.Add(lb);
        }
    }
}