|
Embed ASP.Net DataGrid Control Inside Another DataGrid Control
We have been trying to bring you some basic to advanced techniques that you can
use to format the view for ASP.Net DataGrid control.
In the same series we bring you another article that will show how you can
exploit the flexible architecture of DataGrid control to embed a
DataGrid control inside another DataGrid control to
create, so called, MasterDetail view of your data.
You can bind your data to following kind of columns.
-
BoundColumn
-
ButtonColumn
-
EditCommandColumn
-
HyperLinkColumn
-
TemplateColumn
The first four column types provide a predefined kind of output which is prety
much self explanatory from their names. It is the fifth type, TemplateColumn
which provides the place holder for embedding any type of controls inside the
DataGrid. We will use this column to embed our outer DataGrid. The example we
have shown in this article display regional monthly sales of company in the
embeded DataGrid inside the anual sales DataGrid.
<asp:DataGrid ID="RagionalSales_Grid" Runat="server" DataSource="<%# m_dsRegionalSalesMain %>"
AutoGenerateColumns="False" PageSize="1" AllowPaging="True" CellPadding="4"
BorderColor="#CC9966" BorderStyle="None" BorderWidth="1px" BackColor="White">
<SelectedItemStyle Font-Bold="True" ForeColor="#663399" BackColor="#FFCC66"></SelectedItemStyle>
<AlternatingItemStyle Font-Bold="True" ForeColor="Maroon" BackColor="White"></AlternatingItemStyle>
<ItemStyle Font-Bold="True" ForeColor="#330099" BackColor="White"></ItemStyle>
<HeaderStyle Font-Bold="True" ForeColor="#FFFFCC" BackColor="#990000"></HeaderStyle>
<FooterStyle ForeColor="#330099" BackColor="#FFFFCC"></FooterStyle>
<Columns>
<asp:BoundColumn DataField="RegionName" SortExpression="RegionName" HeaderText="Region Name">>
</asp:BoundColumn>
<asp:BoundColumn DataField="SaleYear" SortExpression="SaleYear" HeaderText="Year">
</asp:BoundColumn>
<asp:TemplateColumn HeaderText="Monthly Sales">
<ItemTemplate>
<asp:DataGrid ID="MonthlySales_Grid" Runat="server" AllowPaging="False"
AllowSorting="False" AutoGenerateColumns="False"
ShowHeader="False" BorderColor="#DEBA84" CellPadding="3" CellSpacing="2"
BorderStyle="None" BackColor="#DEBA84" BorderWidth="1px">
<ItemStyle ForeColor="#8C4510" BackColor="#FFF7E7"></ItemStyle>
<Columns>
<asp:BoundColumn DataField="SaleMonth"></asp:BoundColumn>
<asp:BoundColumn DataField="TotalSale" DataFormatString="{0:c2}">
</asp:BoundColumn>
</Columns>
</asp:DataGrid>
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
<PagerStyle HorizontalAlign="Center" ForeColor="#330099" BackColor="#FFFFCC" Mode="NumericPages">
</PagerStyle>
</asp:DataGrid>
There is only one tiny problem here. When you embed a DataGrid inside
TemplateColumn, you don't get the ability to use the control wizard to format
the inside grid. But you can always create the inner grid separately, format it
and then paste it inside the TemplateColumn.
How to bind inner DataGrid to data source?
This is where things get really interesting. The inside grid or also called the
details grid needs a data source for every row of the master grid. Therefore we
need some mechanism such that we can get the details data based on some key
values in the row of the master grid. We can't bind the inside grid to one data
set. So how do we do it. The folowing code shows you the use of ItemBound
event of the Master Data Grid to get the data for details grid and bind it to
the control. The one very important thing that code demonstrates is that how
can you add event handlers for the inner grid. The problem is that inside
DataGrid object does not get created before the outside grid. Therefore you
can't add the event handlers at the design view. If you try to do it, the code
will throw run time exception that the object refrence does not exist for inner
DataGrid.
private void OnMainGridDataBound(object sender, DataGridItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem ||
e.Item.ItemType == ListItemType.Item)
{
// Get data for that year and region and create data set
Control obCtl = e.Item.FindControl("MonthlySales_Grid");
if (null != obCtl && obCtl is DataGrid)
{
// Bind this grid to monthly sales data..
DataRowView drv = (DataRowView)e.Item.DataItem;
int iRegionID = Convert.ToInt32(drv["Region_id"]);
int iYear = Convert.ToInt32(drv["SaleYear"]);
DataSet ds = this.GetMonthlySalesData(iRegionID, iYear);
DataGrid dg = (DataGrid)obCtl;
dg.ItemDataBound +=
new DataGridItemEventHandler(this.OnMonthlySalesGridDataBound);
dg.DataSource = ds;
dg.DataBind();
}
}
}
private void OnMonthlySalesGridDataBound(object sender, DataGridItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem ||
e.Item.ItemType == ListItemType.Item)
{
// Get the value for first column representing month.
int iMonth = Convert.ToInt32(e.Item.Cells[0].Text);
e.Item.Cells[0].Text = this.GetMonth(iMonth);
}
}
|