GridView column header merging in ASP.NET






4.97/5 (23 votes)
This article explains how we can merge column header and change cell background color for GridView control in Asp.net
Introduction
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.
Requirement
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.
Solution
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
and nd
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.
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);
timeSheet.Rows.Add(dataRow);
currentDate = currentDate.AddDays(1);
}
//Binding time sheet table with data grid view
timeSheetGrid.DataSource = timeSheet;
timeSheetGrid.DataBind();
}
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.
- Changing the
GridView
cell background colors. - Merging
GridView
column headers
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;
break;
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);
break;
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);
break;
}
}
}
}
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);
}
else
{
cell.Text = header.Key.ToString();
if (!cell.Text.Contains("DENTRY"))
{
cell.ColumnSpan = 3;
}
}
gridviewRow.Cells.Add(cell);
}
// 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:
<table>
<tbody><tr>
<td>
<asp:button id="btnShow" runat="server"
text="Show" onclick="btnShow_Click">
</asp:button></td>
</tr>
<tr>
<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%"
onrowcreated="timeSheetGrid_RowCreated"
onrowdatabound="timeSheetGrid_RowDataBound">
<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"
horizontalalign="Center">
<rowstyle backcolor="white" forecolor="black"
wrap="false" font-size="Small">
<selectedrowstyle backcolor="#E2DED6" font-bold="True"
forecolor="#333333">
<sortedascendingcellstyle backcolor="#E9E7E2">
<sortedascendingheaderstyle backcolor="#5216C8C">
<sorteddescendingcellstyle backcolor="#FFFDF8">
<sorteddescendingheaderstyle backcolor="#6F8DAE">
</sorteddescendingheaderstyle>
</sorteddescendingcellstyle>
</sortedascendingheaderstyle>
</sortedascendingcellstyle>
</selectedrowstyle>
</rowstyle>
</pagerstyle>
</headerstyle>
</footerstyle>
</editrowstyle>
</asp:gridview>
</asp:panel>
</td>
</tr>
</tbody>
</table>
Conclusion
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.