This option expands on a code snippet I found at 123aspx.com. This approach uses the DataGrid's ItemCreated event, and works by adding subheading rows to the DataGrid when it is detected that the next value of the grouping column is different from the current value. This option achieves the same look as the second option, but without having to manipulate the DataGrid’s data source before databinding. You need to use both the ItemCreated and ItemDataBound events. Since the ItemCreated event occurs before the ItemDataBound event, we need to set things up for the next DataGridItem.
Listing 4: Manipulating the DataGrid
private string subheading = "";
private bool createsub = false;
// This method will peek ahead in the datasource to determine whether the next
// item will need a new subheading
private void DataGrid1_ItemDataBound(object sender, DataGridItemEventArgs e)
{
switch (e.Item.ItemType)
{
case ListItemType.Header:
case ListItemType.AlternatingItem:
case ListItemType.Item:
DataTable dt = (DataTable)((DataGrid)sender).DataSource;
// header or Subheading column value will change in next row
if ((e.Item.ItemIndex == -1) ||
(e.Item.ItemIndex+1 < dt.Rows.Count &&
dt.Rows[e.Item.ItemIndex+1]["SubHeading"].ToString() !=
dt.Rows[e.Item.ItemIndex]["SubHeading"].ToString()))
{
// get next subheading value
subheading = dt.Rows[e.Item.ItemIndex+1]["SubHeading"].ToString();
createsub = true;
}
else
createsub = false;
break;
}
}
// This method will create a subheading row if needed
private void DataGrid1_ItemCreated(object sender, DataGridItemEventArgs e)
{
switch (e.Item.ItemType)
{
case ListItemType.AlternatingItem:
case ListItemType.Item:
if (createsub)
{
DataGrid dg = (DataGrid)sender;
TableCell tc = new TableCell();
tc.Controls.Add(new LiteralControl(subheading));
tc.ColumnSpan = e.Item.Cells.Count;
tc.Attributes.Add("align", "left");
tc.Font.Bold = true;
tc.BackColor = Color.FromArgb(220, 220, 220);
DataGridItem di =
new DataGridItem(e.Item.ItemIndex+1, 0, ListItemType.Item);
di.Cells.Add(tc);
Table t = (Table)dg.Controls[0];
t.Rows.Add(di);
}
break;
default:
break;
}
}
I hope that these methods will be useful tools in your future projects. A working sample of each option is available in the accompanying code download. For simplicity, the code samples use an Access database rather than a SQL Server database.