Click here to Skip to main content
15,066,084 members
Articles / Web Development / ASP.NET
Posted 28 Aug 2012

Tagged as


46 bookmarked

GridView column header merging in ASP.NET

Rate me:
Please Sign up or sign in to vote.
4.97/5 (25 votes)
4 Sep 2012CPOL3 min read
This article explains how we can merge column header and change cell background color for GridView control in


The ASP.NET GridView data control is a very rich tool for displaying tabular data in web applications and also it is easy to achieve a great degree of customization with this control. In this article, we will examine how to merge a grid view column header and highlight the grid cells for a timesheet application. There are several ways to achieve this, we are going to see one among them. Hope this will be useful for those who work with timesheet kind of applications.


We have a requirement to create an ASP.NET webpage to display the timesheet summary details in tabular format as shown in figure 1. Each Employee Name header should be split into three columns as In Time, Out Time, and Status. Personal leaves and weekend holiday cells should be highlighted with colors as shown below. 

Image 1

Figure 1.


The above requirement can be achieved through the ASP.NET GridView data control. GridView row objects are created before the GridView control is rendered on to the page. Most cell formatting activities can be achieved by capturing the RowDataBou<code>nd and RowCreated events. 

Using the code  

Let’s create a sample timesheet web page to explain a solution for this problem. To get this first we have to populate sample timesheet data using code. Please download the attached source code and go through the data manager class functionality to populate employee and timesheet data using data tables.

Next, we will bind timesheet data to a GridView control. Before binding we should customize the data source table as follows using employee and timesheet data. Refer to the following table and code. 

Image 2

Figure 2.

Now we will see the code to populate the GridView. The following code reads the employee and timesheet data from the sample data tables and generates a new timesheet data table as shown in the above figure.    

private string _seperator = "|";

protected void btnShow_Click(object sender, EventArgs e)
  // Reading employee data
  DataTable employeeData = DataManager.GetEmployeeData();
  // Reading time sheet data for the employee for a data range
  DataTable timeSheetData = DataManager.GetTimeSheetData();

  // Creating a customized time sheet table for binding with data grid view
  var timeSheet = new DataTable("TimeSheet");

  timeSheet.Columns.Add("DENTRY" + _seperator + "");

  // creating colum header for each employee data
  foreach (DataRow item in employeeData.Rows)
    string columnName = item["EMPLOYEENAME"].ToString().Trim();
    timeSheet.Columns.Add(columnName + _seperator + "InTime");
    timeSheet.Columns.Add(columnName + _seperator + "OutTime");
    timeSheet.Columns.Add(columnName + _seperator + "Status");

   // setting start date
   DateTime currentDate = Convert.ToDateTime("05/21/2012");

   //creating 10 days time sheet data for each employee
   for (int i = 0; i < 9; i++)
     var dataRow = timeSheet.NewRow();
     FillTimeSheetRow(timeSheetData, employeeData, currentDate, dataRow);
     currentDate = currentDate.AddDays(1);

   //Binding time sheet table with data grid view
   timeSheetGrid.DataSource = timeSheet;

private void FillTimeSheetRow(DataTable timeSheetData, 
        DataTable employees, DateTime currentDate, DataRow dataRow)
     dataRow["DENTRY" + _seperator + 
             ""] = currentDate.ToString("dd-MMM-yyyy");

      foreach (DataRow row in employees.Rows)
           string columnName = row["EMPLOYEENAME"].ToString().Trim();
           string employeeId = (row["EMPLOYEEID"]).ToString().Trim();

            var dayStatus = "";
            // updating status as holiday for week ends
             if (currentDate.DayOfWeek.ToString() == "Saturday" || 
                     currentDate.DayOfWeek.ToString() == "Sunday")
                  dayStatus = "HDAY";

              // Fetching time sheet entry for the current data from time sheet data
               DataRow[] result = timeSheetData.Select("EMPLOYEEID='" + employeeId + 
                     "' AND DENTRY='" + currentDate.ToShortDateString() + "'");

                if (result.Length != 0)
                    string status = result[0]["STATUS"].ToString();
                    dataRow[columnName + "|InTime"] = result[0]["INTIME"].ToString();
                    dataRow[columnName + "|OutTime"] = result[0]["OUTTIME"].ToString();
                    dayStatus = status;
                dataRow[columnName + "|Status"] = dayStatus;

After modifying the timesheet data table, we have to capture two events (RowDataBound and RowCreated) for changing the cell background color and merging the column headers. 

  1. Changing the GridView cell background colors.
  2. Before the timesheet GridView control can be rendered on to the page, we have to capture the RowDataBound event. And it is triggered whenever the GridViewRow object is bound to timesheet data. A GridviewRowEventArgs object is passed to the handler method, which will help us access properties of every row. After getting the row cells we can check for the cell text property and we can change the background color for that particular cell using the BackColor property. Refer to the following code snippet.

    protected void timeSheetGrid_RowDataBound(object sender, GridViewRowEventArgs e)
      //number of cells in the row
      int cellCount = e.Row.Cells.Count;
      //iterating through every cells and check for the status for each employees
      for (int item = 3; item < cellCount; item = item + 3)
        if (e.Row.Cells != null)
          var cellText = e.Row.Cells[item].Text;
          switch (cellText)
           case "WDAY"://Working Day
            e.Row.Cells[item].VerticalAlign = VerticalAlign.Middle;
           case "LEAVE"://Leave
            e.Row.Cells[item].VerticalAlign = VerticalAlign.Middle;
            e.Row.Cells[item].BackColor = Color.FromArgb(255, 255, 000);
            e.Row.Cells[item - 1].BackColor = Color.FromArgb(255, 255, 000);
            e.Row.Cells[item - 2].BackColor = Color.FromArgb(255, 255, 000);
           case "HDAY"://Holiday
            e.Row.Cells[item].VerticalAlign = VerticalAlign.Middle;
            e.Row.Cells[item].BackColor = Color.FromArgb(255, 0, 0);
            e.Row.Cells[item - 1].BackColor = Color.FromArgb(255, 0, 0);
            e.Row.Cells[item - 2].BackColor = Color.FromArgb(255, 0, 0);
  3. Merging GridView column headers
  4. Just like RowDataBound, the RowCreated event gets fired whenever a row in the GridView is created. This helps us code custom functionality to a grid row and allows to implement code to merge cell headers depending on the RowType of the GridviewRowEventArgs object arguments. After customization we can hide the default header row by making the Visible property false. Refer to the following code snippet:

    protected void timeSheetGrid_RowCreated(object sender, GridViewRowEventArgs e)
      //If row type= header customize header cells
      if (e.Row.RowType == DataControlRowType.Header)
      CustomizeGridHeader((GridView)sender, e.Row, 2);
    private void CustomizeGridHeader(GridView timeSheetGrid, 
                 GridViewRow gridRow, int headerLevels)
         for (int item = 1; item <= headerLevels; item++)
            //creating new header row
            GridViewRow gridviewRow = new GridViewRow(0, 0, 
            DataControlRowType.Header, DataControlRowState.Insert);
            IEnumerable<IGrouping<string,>> gridHeaders = null;
            //reading existing header 
            gridHeaders = gridRow.Cells.Cast<tablecell>()
            .Select(cell => GetHeaderText(cell.Text, item))
            .GroupBy(headerText => headerText);
            foreach (var header in gridHeaders)
                TableHeaderCell cell = new TableHeaderCell();
                if (item == 2)
                    cell.Text = header.Key.Substring(header.Key.LastIndexOf(_seperator) + 1);
                    cell.Text = header.Key.ToString();
                    if (!cell.Text.Contains("DENTRY"))
                        cell.ColumnSpan = 3;
            // Adding new header to the grid
            timeSheetGrid.Controls[0].Controls.AddAt(gridRow.RowIndex, gridviewRow);
        //hiding existing header
        gridRow.Visible = false;
    private string GetHeaderText(string headerText, int headerLevel)
        if (headerLevel == 2)
            return headerText;
        return headerText.Substring(0, headerText.LastIndexOf(_seperator));

    Now we will see the rest of the code-behind for the GridView control:

    <asp:button id="btnShow" runat="server" 
          text="Show" onclick="btnShow_Click">
    <td><asp:panel id="pnlContent" scrollbars="Auto" 
        style="background-color: white; width: 980px; height: 500px; " runat="server">
    <asp:gridview id="timeSheetGrid" runat="server" cellpadding="4" 
            forecolor="#333333" gridlines="Both" bordercolor="#738DA5" 
            cellspacing="1" width="100%" 
       <editrowstyle backcolor="#999999">
       <footerstyle backcolor="#5D7B9D" 
              font-bold="True" forecolor="White">
       <headerstyle backcolor="#465c71" font-bold="False" 
          forecolor="White" wrap="false" font-size="Small">
       <pagerstyle backcolor="#284775" forecolor="White" 
       <rowstyle backcolor="white" forecolor="black" 
              wrap="false" font-size="Small">
       <selectedrowstyle backcolor="#E2DED6" font-bold="True" 
       <sortedascendingcellstyle backcolor="#E9E7E2">
       <sortedascendingheaderstyle backcolor="#5216C8C">
       <sorteddescendingcellstyle backcolor="#FFFDF8">
       <sorteddescendingheaderstyle backcolor="#6F8DAE">


Download the above sample web application and go through the entire code and inline comments for better understanding of this article. If you have any questions, please contact me through mail or the discussion board below.


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


About the Author

Vinod Viswanath
Engineer GE Oil & Gas
India India
Vinod is Microsoft Certified Professional in WebDev 4, And Lead Engineer by profession. He has more than 8+ yrs of experience in IT industry working on Microsoft Technologies. Prefer to be judged not on his job title but by ability to do a good job of what he is supposed to do.

Technical experience most specifically C#,Ado.Net,Asp.Net, WCF, Sql Server,JavaScript,XML,Web services.

Comments and Discussions

QuestionGridView column header merging in ASP.NET Pin
Member 127296919-Sep-16 0:43
MemberMember 127296919-Sep-16 0:43 
GeneralThanks a lot bro..U did really a nice work. Pin
Jaya Krishna Yarlagadda17-Aug-15 17:37
MemberJaya Krishna Yarlagadda17-Aug-15 17:37 
QuestionEditable gridview with multiple column headers Pin
Member 95859818-Jan-14 22:41
MemberMember 95859818-Jan-14 22:41 
SuggestionA good article!- In MY Humble Opinion Pin
rajatmig2926-Feb-13 19:58
Memberrajatmig2926-Feb-13 19:58 
Questionsolid Pin
manoj aroraa4-Jan-13 23:46
Membermanoj aroraa4-Jan-13 23:46 
Questionnice one Pin
Mr. Tapan Kumar10-Oct-12 9:54
MemberMr. Tapan Kumar10-Oct-12 9:54 
GeneralMy vote of 3 Pin
Mr. Tapan Kumar10-Oct-12 9:53
MemberMr. Tapan Kumar10-Oct-12 9:53 
GeneralNice work.. Pin
Shaibujan14-Sep-12 21:15
MemberShaibujan14-Sep-12 21:15 
Generalgood job. Pin
ravisonaiya6-Sep-12 22:02
Memberravisonaiya6-Sep-12 22:02 
GeneralRe: good job. Pin
Vinod Viswanath6-Sep-12 22:15
MemberVinod Viswanath6-Sep-12 22:15 
Questionvinod you rock again ..!!!! Pin
pankajcode5-Sep-12 6:55
Memberpankajcode5-Sep-12 6:55 
QuestionNice learning Pin
wsc09184-Sep-12 17:03
Memberwsc09184-Sep-12 17:03 
GeneralMy vote of 5 Pin
Libish Varghese Jacob2-Sep-12 5:48
MemberLibish Varghese Jacob2-Sep-12 5:48 
GeneralMy vote of 5 Pin
macsys1-Sep-12 19:24
Membermacsys1-Sep-12 19:24 
GeneralMy vote of 1 Pin
Member 894945029-Aug-12 21:13
MemberMember 894945029-Aug-12 21:13 
GeneralRe: My vote of 1 Pin
Kenneth Haugland1-Sep-12 10:51
professionalKenneth Haugland1-Sep-12 10:51 
GeneralRe: My vote of 1 Pin
ednrg4-Sep-12 10:03
Memberednrg4-Sep-12 10:03 
GeneralMy vote of 5 Pin
Christian Amado29-Aug-12 11:03
professionalChristian Amado29-Aug-12 11:03 
GeneralMy vote of 5 Pin
Steve Xaviour29-Aug-12 0:52
MemberSteve Xaviour29-Aug-12 0:52 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.