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:

///<summary>/// This is our custom render method for the grid header item
///</summary>///<paramname="writer"></param>///<paramname="ctl"></param>privatevoid 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):

Comments and Discussions

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)

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.

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.

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

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.