The Overview
In this article I am going to show you one technique for adding
a "drill down" feature to a DataGrid.
In the code that accompanies this article, the summary page consists of a simple
DataGrid control, with three columns. The DataGrid
is bound in the code-behind to a data reader representing the Categories in
the Northwind database. The third column contains an indication of the
number of products that are in the category, rendered as a Link Button.
Clicking the Link Button causes the page to drill-down to the details.
In its drill down state, the details are rendered as a separate DataGrid
control; that is as a DataGrid nested inside
the outer Categories DataGrid.
Shown here in the first image is the "Summary" page; the
second image shows how that page renders itself after you click on
the Link Button for Grains/Cereals (row 5).
| DataGrid In Summary
Mode |
 |
DataGrid in Detail Mode |
 |
There are two tricks here: First, the
Link Button is defined as an Edit Command and second, the detail or drill down
data is implemented as a User Control. The later is not technically
required; you could implement the detail data in the same page as the summary
page, I just found the User Control created code that was easier for me to
understand and maintain.
The first point, that the Link Button is a "Edit Command" is important
to this technique. The DataGrid gives
us two templates that we can use to render the detail data: <ItemTemplate>
and <EditItemTemplate>. If an <ItemTemplate>
exists for a column, then all details rows are rendered using the <ItemTemplate>,
except for the row that is indicated by the EditItemIndex
property. This row will be rendered using the <EditItemTemplate>.
In this case, I only defined an <EditItemTemplate>
for the third column; the one which will contain the detail data. Since
I didn't define an <EditItemTemplate>
for the other columns, they default to the normal <ItemTemplate>.
The <EditItemTemplate>
| Template for Drill Down Column |
<asp:templatecolumn>
<itemtemplate>
<asp:linkbutton RUNAT="server"
TEXT='<%#
"Products in Category: " & DataBinder.Eval(Container, "DataItem.productsInCategoryCnt")
%>'
COMMANDNAME="Edit"
ID="Linkbutton1"
>
</asp:linkbutton>
</itemtemplate>
<edititemtemplate>
<DNJ:products
ID="Products"
CATEGORYID='<%# DataBinder.Eval(Container, "DataItem.CategoryID")
%>'
RUNAT="server">
</DNJ:products>
</edititemtemplate> </asp:templatecolumn> |
As an <ItemTemplate>, the Link Button
is bound to the literal "Products in Category" concatenated with the number
of products in the category as found in the underlying DataSource.
As an <EditItemTemplate>, the user
control <DNJ:products> is rendered.
The keys here are the user control exposes an attribute/property called
CategoryID and this attribute is bound
to the CategoryID for the current item.
The User Control
The User Control is again a simple DataGrid;
you can accomplish the same thing with any of the data repeating controls.
As seen above, the control exposes the property CategoryID
as an attribute. As you can see from the code-snippet below, the Set
routine for this property calls the function DataBind().
This routine in-turn creates an SQL statement that retrieves the Product records
that have the CategoryID that is being set. This
SQL then creates a data reader that is used as the DataSource
for the User Control's DataGrid.
| Property of User
Control |
Private c_CategoryID
As Integer
Public Property CategoryID() As
Integer
Get
Return
c_CategoryID
End Get
Set(ByVal Value
As Integer)
c_CategoryID =
Value
BindData()
End Set
End Property |
In Action
If you were to debug the code in step-mode,
you would see something like this happen.
First the page is loaded. It is not a PostBack,
so the DataGrid is bound to a simple data reader
representing the Categories table. If you then click on one of the drill
down links, the page will re-post. Since it is a PostBack,
the data is not immediately bound to the data, but the code associated with
the "Edit Command" is run. This code sets the EditItemIndex to
the row that you click, then fires the BindData
function. Again the DataGrid is bound
to the categories tables, but this time since the EditItemIndex
is set, the <EditItemTemplate> fires,
which in turn instantiates the User Control. After the User Control
instantiates, the CategoryID attribute
is set to the CategoryID of the row selected.
This in turn causes the Set code in the User
Control's property CategoryID to fire, which
in turn causes the User Control's DataGrid
to be bound to a data reader representing the Products that have the specified
CategoryID.
Summary
And that's all there is to it. In this article, I've shown
you one technique that allows you to 'drill-down' from summary data in a DataGrid,
to the details data that makes up the summary data.