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.

GeneralSimplified and improved version the solution described above.memberMykola Tarasyuk13 Jun '07 - 3:33 
I try to simplify and improve the solution described above. Now it works with autogenerated columns, doesn't harm sorting and paging.
http://marss.co.ua/MergingGridViewHeaderColumns.aspx

QuestionProblem with page [modified]membermaya_zakry30 May '07 - 19:59 
Hi all.. and irwansyah
how do i remove paging below my extra header when the datagrid allowpaging is on? i need the peging, but i only need 1 at the below... it seems like extra header puts extra peging on top.. how to remove it..please response asap.. HUWAAAA.. see my double paging grid :-
http://picasaweb.google.com/maya.zakry/ScreenShots/photo#5050533591981982914[^]
 

 
-- modified at 22:23 Monday 4th June, 2007
GeneralProblem with dynamic columnsmembersatejprabhu25 Feb '07 - 22:30 
Hi,
 
i m generating dynamic columns at run time ... how do i add/merge columns on the fly....
 
satej prabhu
QuestionWhat about Sorting and Paging ?membercodeprojectmitu9 Nov '06 - 23:51 
Hi
Sorting and Paging functions are not working, even the properties are true. Is there any work around to solve this problem?
Thanks
 
A programmer

GeneralSorting Doesent work where RowSpan=2memberAnand Morbia14 Oct '06 - 4:49 
Sorting Doesent work where RowSpan=2
 
Anand Morbia
Distil Technologies
http://www.distiltech.com

GeneralHelp to Merge it in VB.NET version...memberslee_g4 Sep '06 - 22:43 
Can anyone help to merge the data grid by using VB.NET?
 
Thanks/Siew Lee
QuestionSolution for Windows Form DataGridViewmemberC#newcomer18 Aug '06 - 17:04 
/
Hi, Irwansyah:
 
Do you (or anybody else) have a similar solution for DataGridView control which is a Windows form control? There is no
in Win forms. Any suggestins are appreciated.
 
Bo
GeneralThanks (and some critics)membernsimeonov12 Jul '06 - 9:00 
, but on my machine it doesn't render
First of all - thank you for the really helpful article!
 
Some critics:
 
1. in ASPNetDataGridDecorator.cs in private void NewRenderMethod(...) you have to call writer.RenderEndTag(); at the end because it will renter
 
2. absolute positioning (e.g. Grid-style web forms) is sort of awkward - using different fonts or font sizes produces really funny results, so avoid using it - this is a friendly advice.
 
3. in such examples it would be much clearer (and more obvious) without all the nice formatting and colors etc.
 
4. cleaning up the auto-generated "TODO" comments would make the code somewhat better IMO Smile | :)
 
5. separating the functions with at least one blank line improves the readability of your code.
 
but nevertheless this is a great example and article!
 
Thank you again,
Nikolay
GeneralRe: Thanks (and some critics)memberirwansyah12 Jul '06 - 15:25 
OK, Thanks for your critics. For point 2, 3, 4, and 5 I think as an experienced programmer we all knows that and my code is not a real software project code that's why it still contains things like "TODO" comments, etc.
 
As a software developer I prefer a working software then a nice looking source code, especially if the project is a dead-march project or has very tight deadline.
 
thanks,
Irwansyah
GeneralRe: Thanks (and some critics)membernsimeonov12 Jul '06 - 15:43 
I know, I know... I don't like tight deadlines, but I have such more often than enough time to do everything perfect. I just try to keep the stuff as clean as possible, because the more cluttered the code it the more bugs it usually has. That's why I became a bit pedantic on some basic stuff that don't require too much effort, but make my life easier in the "long run".
 
Despite the small bug your code works well and I think I can use it on and off Smile | :)
 
Regards,
Nikolay
GeneralProblem with ItemCommand eventmemberArturo Montoya Rivera23 Mar '06 - 12:50 
It doesnt triger the event!!!!! I created the datagrid columns dinamicaly, and one of the columns is a ButtonColumn, but the event it is not fired Frown | :( help!!!!!
GeneralRe: Problem with ItemCommand eventmemberArturo Montoya Rivera24 Mar '06 - 5:08 
Problem solved, i had to define de columns in the aspx file intead of creating them dinamycally, =)
GeneralRe: Problem with ItemCommand eventmemberJakeanson27 Apr '06 - 23:51 
You should change it as "protected".
GeneralTHANK YOU!membersroh3 Mar '06 - 14:39 
Thank you very much for this extremely useful article!
GeneralProblem with Invisible Columnmembernavinkaus11 Jan '06 - 21:55 
Hi,
I am facing a problem when I want to hide some columns. I used the method which already suggested but using that way It always start hiding columns from last. For example if I want to hide 3rd column and there are total 7 columns,it will hide 7th column instead of 3rd.
 
How can I add hide columns whichever I want ??

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

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