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.
Figure 1.
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<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.
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)
{
DataTable employeeData = DataManager.GetEmployeeData();
DataTable timeSheetData = DataManager.GetTimeSheetData();
var timeSheet = new DataTable("TimeSheet");
timeSheet.Columns.Add("DENTRY" + _seperator + "");
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");
}
DateTime currentDate = Convert.ToDateTime("05/21/2012");
for (int i = 0; i < 9; i++)
{
var dataRow = timeSheet.NewRow();
FillTimeSheetRow(timeSheetData, employeeData, currentDate, dataRow);
timeSheet.Rows.Add(dataRow);
currentDate = currentDate.AddDays(1);
}
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 = "";
if (currentDate.DayOfWeek.ToString() == "Saturday" ||
currentDate.DayOfWeek.ToString() == "Sunday")
{
dayStatus = "HDAY";
}
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. 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)
{
int cellCount = e.Row.Cells.Count;
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":
e.Row.Cells[item].VerticalAlign = VerticalAlign.Middle;
break;
case "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":
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;
}
}
}
}
- Merging
GridView
column headers 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 (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++)
{
GridViewRow gridviewRow = new GridViewRow(0, 0,
DataControlRowType.Header, DataControlRowState.Insert);
IEnumerable<IGrouping<string,>> gridHeaders = null;
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);
}
timeSheetGrid.Controls[0].Controls.AddAt(gridRow.RowIndex, gridviewRow);
}
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.