Click here to Skip to main content
Click here to Skip to main content

Merge DataGrid Header

By , 26 Oct 2004
 

Sample Image

Sample Image

Introduction

This article describes the technique to merge the header of a DataGrid by redirecting the Render method of the DataGrid items.

Background

I found many times the need to merge the header of a DataGrid. So, when I was having spare time, I tried to find a way to do it, and here it is. I know that if you need to merge headers, you can use the Repeater control instead. But if you are fond of DataGrid (just like me), or may be you already used DataGrid, then this article is for you.

Using the code

When rendered, a DataGrid will be converted into a HTML Table element and the header will be the first HTML TR element. So, to have a merged header, we need to have control in the rendering of the header. This can be achieved by redirecting the Render method of the DataGrid header using the SetRenderMethodDelegate of the DataGrid header on ItemCreated event, like this:

private void Datagrid1_ItemCreated(object sender, 
          System.Web.UI.WebControls.DataGridItemEventArgs e) 
{ 
    //*** Examine if the item created is the header item 
    ListItemType lit = e.Item.ItemType; 
    if(ListItemType.Header == lit) 
    { 
        //*** Redirect the default header rendering method to our own method 
        e.Item.SetRenderMethodDelegate(new RenderMethod(NewRenderMethod)); 
    } 
}

And here is our own Render method:

/// <summary> 
/// This is our custom render method for the grid header item 
/// </summary> 
/// <param name="writer"></param> 
/// <param name="ctl"></param> 
private void NewRenderMethod(HtmlTextWriter writer, Control ctl) 
{ 
    //***  We don't need to write the <TR> tag
    //     because it's already written by the writer 
    //     so now we write the Name column 
    writer.Write("<TD colspan=\"3\" align=\"center\">Name</TD>\n"); 

    //***  The Age column must have the rowspan attribute
    //     and must be rendered inside the 
    //     first row so it will centered vertically 
    TableCell cell = (TableCell)ctl.Controls[ctl.Controls.Count-1]; 
    cell.Attributes.Add("rowspan","2"); 
    cell.RenderControl(writer); 

    //***     Now we close the first row, so we can insert the second one 
    writer.Write("</TR>\n"); 

    //***  Add the style attributes that was defined in design time 
    //     to our second row so they both will have the same appearance 
    DataGrid1.HeaderStyle.AddAttributesToRender(writer); 

    //***     Insert the second row 
    writer.RenderBeginTag("TR"); 

    //***  Render all the cells that was defined
    //     in design time, except the last one 
    //     because we already rendered it above 
    for(int i=0; i<= ctl.Controls.Count-2; i++) 
    { 
        ctl.Controls[i].RenderControl(writer); 
    } 

    //***  We don't need to write the </TR> close tag
    //     because the writer will do that for us 
    //     and so we're done :) 
}

I have created a decorator class to decorate a DataGrid (ASPNetDatagridDecorator class) to have a merge header, and all you need to do is define the header cell like this (you can use the auto format feature, but doesn't work for all):

private void Page_Load(object sender, System.EventArgs e)
{
    // Put user code to initialize the page here
    if(!this.IsPostBack)
    {
        TableCell cell = null;
        DataGrid1.DataSource = GetData();
        DataGrid1.DataBind(); 

        m_add.DatagridToDecorate = Datagrid2;
        ArrayList header = new ArrayList();

        // cell = new TableCell();
        // cell.Text = "Code";
        // cell.RowSpan = 2;
        // cell.HorizontalAlign = HorizontalAlign.Center;
        // header.Add(cell);

        cell = new TableCell();
        cell.Text = "Name";
        cell.RowSpan = 2;
        cell.HorizontalAlign = HorizontalAlign.Center;
        header.Add(cell);

        cell = new TableCell();
        cell.Text = "Name";
        cell.ColumnSpan = 3;
        cell.HorizontalAlign = HorizontalAlign.Center;
        header.Add(cell);

        cell = new TableCell();
        cell.Text = "Age";
        cell.RowSpan = 2;
        cell.HorizontalAlign = HorizontalAlign.Center;
        header.Add(cell);

        cell = new TableCell();
        cell.Text = "School";
        cell.ColumnSpan = 3;
        cell.HorizontalAlign = HorizontalAlign.Center;
        header.Add(cell);

        cell = new TableCell();
        cell.Text = "Religion";
        cell.RowSpan = 2;
        cell.HorizontalAlign = HorizontalAlign.Center;
        header.Add(cell);

        m_add.AddMergeHeader(header);

        Datagrid2.DataSource = GetData();
        Datagrid2.DataBind();

    }

}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

irwansyah
Web Developer
Indonesia Indonesia
Member
Irwansyah is a web developer currently using ASP.Net. Irwansyah main interests lie in developing business application framework.
 
Irwansyah intends to work overseas one day and explore the world till the end of the world.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 1membershankar.koppella16 Aug '10 - 0:20 
xyz
QuestionProblem with row selectingmemberMember 25375619 Jul '09 - 11:22 
I have created the extra header row which has caused another problem. When I select a row, the index is starting with 0 but, it is returning the row before it( i.e. row 2 is returning row 1 data). I can not get it to return the first row data unless I select row two. I can not get the last row data at all. Has anyone run into this and how do I resolve it?
 
This is the code I used to create the new header (GetDayorDate() is a function to return the day or date information of the person I was loading the grid for)
 
Public Sub createheader()
 
Dim dt As DateTime
 

 

'If (e.Row.RowType = DataControlRowType.Header) Then
Dim gvheader As GridView = Me.grdtime
Dim gvr As GridViewRow = New GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Insert)
Dim tc1 As New TableCell
tc1.Text = "Time Data"
tc1.ColumnSpan = "9"
tc1.CssClass = "gentxt"
'tc1.ForeColor = Color.CornflowerBlue
gvr.Cells.Add(tc1)
 
tc1 = New TableCell
tc1.Text = GetDayorDate("Monday", 0) & "<br>" & GetDayorDate("Monday", 1)
 
' tc1.Text = dt.DayOfWeek.ToString & "<br>" & GetDayorDate("Monday", 1)
tc1.ColumnSpan = "2"
tc1.CssClass = "gentxt"
'tc1.ForeColor = Color.CornflowerBlue
gvr.Cells.Add(tc1)
 
tc1 = New TableCell
tc1.Text = GetDayorDate("Tuesday", 0) & "<br>" & GetDayorDate("Tuesday", 1)
tc1.ColumnSpan = "2"
tc1.CssClass = "gentxt"
'tc1.ForeColor = Color.CornflowerBlue
gvr.Cells.Add(tc1)
 
tc1 = New TableCell
tc1.Text = GetDayorDate("Wednesday", 0) & "<br>" & GetDayorDate("Wednesday", 1)
tc1.ColumnSpan = "2"
tc1.CssClass = "gentxt"
'tc1.ForeColor = Color.CornflowerBlue
gvr.Cells.Add(tc1)
 
tc1 = New TableCell
tc1.Text = GetDayorDate("Thursday", 0) & "<br>" & GetDayorDate("Thursday", 1)
tc1.ColumnSpan = "2"
tc1.CssClass = "gentxt"
'tc1.ForeColor = Color.CornflowerBlue
gvr.Cells.Add(tc1)
 
tc1 = New TableCell
tc1.Text = GetDayorDate("Friday", 0) & "<br>" & GetDayorDate("Friday", 1)
tc1.ColumnSpan = "2"
tc1.CssClass = "gentxt"
'tc1.ForeColor = Color.CornflowerBlue
gvr.Cells.Add(tc1)
 
tc1 = New TableCell
tc1.Text = GetDayorDate("Saturday", 0) & "<br>" & GetDayorDate("Saturday", 1)
tc1.ColumnSpan = "2"
tc1.CssClass = "gentxt"
'tc1.ForeColor = Color.CornflowerBlue
gvr.Cells.Add(tc1)
 
tc1 = New TableCell
tc1.Text = GetDayorDate("Sunday", 0) & "<br>" & GetDayorDate("Sunday", 1)
tc1.ColumnSpan = "2"
tc1.CssClass = "gentxt"
'tc1.ForeColor = Color.CornflowerBlue
gvr.Cells.Add(tc1)
 
tc1 = New TableCell
tc1.Text = "Project<br>Totals"
tc1.ColumnSpan = "2"
tc1.CssClass = "gentxt"
'tc1.ForeColor = Color.CornflowerBlue
gvr.Cells.Add(tc1)
 
gvheader.Controls(0).Controls.AddAt(0, gvr)
GeneralPage PostBackmemberGoast25212 Mar '09 - 5:01 
Whene Page goes to server (I press button on page), header disapeared....
GeneralPage PostBackmemberMarichamyK9 Jul '09 - 18:57 
Hi
 
I'm also facing same problem.
did u get any solution for this please mail me
samy.kanagaraj@gmail.com
GeneralRe: Page PostBackmemberisunshine4 Jan '10 - 11:17 
The reason is that the ItemDataBound is called only once for the initial load. To keep it intact after the postback, move the SetRenderMethodDelegate from ItemDataBound to ItemCreated event.
 
aspx:
<asp:datagrid OnItemCreated="dg_ItemCreated" ... />
 
aspx.cs:
protected void dgMeasure3AndUp_ItemCreated(object o, DataGridItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Header)
{
e.Item.SetRenderMethodDelegate(RenderCustomTH);
}
}
GeneralExcellent work...Keep it upmemberMohammed Hameed27 Jan '09 - 21:30 
Hello Irwansyah,
I m really very much thankful to you. Your code and logic helped me a lot. Once again thank u very much....
 
Be a good professional who shares programming secrets with others.

QuestionAny solution for the sorting the dataGridmemberbpranathi14 Jul '08 - 10:03 
I need the a work around for sorting the columns.
 
Is there any solution.
 
Responce is appreciated.
 
Thanks
GeneralVB Versionmembermeme me20 May '08 - 5:00 
Has anyone got a working VB version? I have spent all day trying to convert it but still can't get it working!
 
Cheers in advance!
GeneralThis moves the grid below the page footer.membertech110 Mar '08 - 5:15 
This was very helpful, and was almost exactly what I was looking for; however, when I implement it, it moves the grid to the very bottom of the page, below all page footer controls that should be below the grid.
 
I've tried manually setting the style using absolute and relative positions, explicitly setting the top, dynamically building the entire grid in C# and adding it to a div or panel tag within the page; and rendering the grid during any event from page_load to page_prerender. The grid always renders at the bottom.
 
Any ideas?
 
Thanks.
Generalproblem when I am creating dynamic gridsmemberForwardmurali20 Sep '07 - 23:08 
how to applicable Double header when I am creating dynamic grids . SetRenderMethodDelegate method is not working
 
muralid.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 27 Oct 2004
Article Copyright 2004 by irwansyah
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid