Question:
Building
a Master/Detail DataGrid - Great Article! How would a template column be
created and included in the DataGrid that appears in the Orders column.
GfWeis
The Answer:
Well, first off...thanks for the compliment. Now, let's cut to the chase. What
you are asking, adding a TemplateColumn to an
embedded DataGrid, can certainly be done. We are going to take a slightly different
approach for this however. In this tutorial I will show you how to embed a DataGrid
in a DataGrid, with a TemplateColumn in the
embedded DataGrid. The design for the embedded DataGrid will actually be done
in the Web Form, and we will call a method in our code behind class to populate
the embedded DataGrid.
Let's Get It On
We will demonstrate building a master/detail DataGrid using the Northwind Customers
and Orders tables. The sample code download has all of the sample code
is in C# and Visual Basic .NET.
First, lets build the Web form user interface. For this we will use a DataGrid
with BoundColumns and TemplateColumns,
similar to the one in the first
article. The result will look like this:

[Run Sample]
From the screenshot you can see that we have three columns, ID, Customer,
and Orders. The Orders column has an embedded DataGrid, which
is made up of two columns, Order ID and a TemplateColumn
displaying the order infomration..
Here is the Web Form code:
<%@ Page language="c#"
Inherits="MasterDetail.CustomerOrderDataGrid" EnableViewState="False"
%>
<HTML>
<body style="font: x-small Verdana, Arial, sans-serif;">
<!-- Begin Web Form -->
<form id="CustomerOrderDataGrid"
method="post" runat="server">
<p><a href="/DayOfDotNet/">Parent
Directory</a></p>
<!-- Begin
DataGrid -->
<asp:DataGrid id="CustomerDataGrid"
runat="server"
AutoGenerateColumns="False"
CellPadding="2"
CellSpacing="0"
Font-Names="Verdana,
Arial, sans-serif"
BorderColor="Black"
BorderWidth="1"
GridLines="Horizontal"
OnItemDataBound="CustomerDataGrid_OnItemDataBound">
<HeaderStyle
Font-Bold="True"
Font-Size="small"
Font-Name="Arial"
BackColor="Maroon"
ForeColor="White" />
<ItemStyle
Font-Size="x-small" />
<AlternatingItemStyle
BackColor="Tan" />
<Columns>
<asp:HyperLinkColumn
DataTextField="CustomerID"
DataNavigateUrlField="CustomerID"
DataNavigateUrlFormatString="OrderDetailDataGrid.aspx?customerid={0}"
HeaderText="ID"
ItemStyle-VerticalAlign="Top"
/>
<asp:TemplateColumn
ItemStyle-VerticalAlign="Top" HeaderText="Customer">
<ItemTemplate>
<b><%#
DataBinder.Eval(Container.DataItem, "CompanyName") %></b><br>
<%#
DataBinder.Eval(Container.DataItem, "Address" ) %><br>
<%#
DataBinder.Eval(Container.DataItem, "City" ) %>,
<%#
DataBinder.Eval(Container.DataItem, "Region") %>
<%#
DataBinder.Eval(Container.DataItem, "PostalCode" ) %><br>
<br>
<%#
DataBinder.Eval(Container.DataItem, "ContactName" ) %><br>
<%#
DataBinder.Eval(Container.DataItem, "ContactTitle" ) %><br>
<%#
DataBinder.Eval(Container.DataItem, "Phone" ) %>
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn
ItemStyle-VerticalAlign="Top"
HeaderText="Orders"
ItemStyle-Width="100%">
<ItemTemplate>
<asp:DataGrid
runat="server"
AutogenerateColumns="False"
Width="100%"
GridLines="Horizontal"
BorderColor="Black"
BorderWidth="1"
Font-Name="Verdana"
Font-Size="x-small"
DataSource='<%#
getOrdersDataSource( (string)DataBinder.Eval(Container.DataItem, "CustomerID")
) %>'>
<HeaderStyle
BackColor="Black"
ForeColor="White"
Font-Bold="True"
/>
<ItemStyle
BackColor="White" />
<AlternatingItemStyle
BackColor="Silver" />
<Columns>
<asp:BoundColumn
DataField="OrderID" HeaderText="Order ID" />
<asp:TemplateColumn>
<ItemTemplate>
<b>Order
Date: </b>
<%#
DataBinder.Eval(Container.DataItem, "OrderDate", "{0:D}"
) %>
<br>
<b>Shipped
Date: </b>
<%#
DataBinder.Eval(Container.DataItem, "OrderDate", "{0:D}"
) %>
<br>
<b>Required
Date: </b>
<%#
DataBinder.Eval(Container.DataItem, "OrderDate", "{0:D}"
) %>
<br>
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:DataGrid>
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:DataGrid>
<!-- End DataGrid -->
</form>
<!-- End Web Form -->
</body>
</HTML> |
In the thrid column, a TemplateColumn, we have
a DataGrid - this is the embedded DataGrid. In this example we have defined
the two columns of the embeded DataGrid as a BoundColumn
and a TemplateColumn. In the TemplateColumn
we define an ItemTemplate, which will control
how each row in this column is rendered. We use the DataBinder to render specified
columns from our data source.
The DataSouce property of the embedded DataGrid
points to a method that we will define in the code behind class.
Break It Down
In the code behind class for the Web Form we will do a couple of things: bind
the CustomerDataGrid server control to the Customers
table from the Northwind database and expose a method to get the DataSource
for the embedded DataGrid.
using
System;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace MasterDetail
{
public class CustomerOrderDataGrid
: System.Web.UI.Page
{
protected DataGrid
CustomerDataGrid;
private DataSet ds
= new DataSet();
private void Page_Load(object
sender, System.EventArgs e)
{
if(!Page.IsPostBack)
{
BindData();
}
}
private
void BindData()
{
string
sqlStmt = "SELECT * FROM Customers; SELECT * FROM Orders";
string
conString = "server=localhost;database=Northwind;uid=sa;pwd=;";
SqlDataAdapter sda = new SqlDataAdapter(sqlStmt,
conString);
sda.Fill(ds);
ds.Tables[0].TableName = "Customers";
ds.Tables[1].TableName = "Orders";
CustomerDataGrid.DataSource = ds.Tables["Customers"];
CustomerDataGrid.DataBind();
}
protected DataView
getOrdersDataSource(string _customerID)
{
DataView _orders = ds.Tables["Orders"].DefaultView;
_orders.RowFilter = "CustomerID='"
+ _customerID + "'";
return
_orders;
}
}
} |
In the SQL statement we select two result sets. When we invoke the data adapter's
Fill() method this will create two DataTables,
one for each result set. For organizational (and anal retentive) purposes, we
set the TableName property of each of the DataTables,
and bind the CustomerDataGrid.
Notice, we declared the DataSet (ds) at the
class-level. This will give us access to the DataSet from the getOrdersDataSource()
method. In the getOrdersDataSource() method
we need to create a DataView that is the default view of the Orders DataTable
from the DataSet. Then we use the DataView.RowFilter
property to filter out all the records except records in the Orders DataTable
that have the same CustomerID value as the CustomerID
for the current row (the value passed into the method from the Web Form).
Summary
In this tutorial we looked at another way to embed a DataGrid a parent DataGrid...a
master/detail DataGrid. In this tutorial we defined the DataGrid in the Web
Form, including defining a TemplateColumn to
use for custom layout. This method of embedding a DataGrid is much less complex,
interms of code, and just as effective.