General solution
Nesting
GridView
controls in ASP.NET were described in that almost “canonical” Microsoft walkthrough [1]. In general, it requires creating of two
GridView
controls: the first one serving as a container or master
GridView1
with its own
DataSource1
(
SqlDataSource
,
AccessDataSource
, etc.) and second "nested"
GridView2
with its underlying
DataSource2
residing within a
TemplateField
in master
GridView1
.
Code snippet [1] inside the
GridView1 RowDataBound
event procedure (
GridView1_RowDataBound
) serves the task of passing a "foreign key" value from
GridView1
to
DataSource2
. In the particular example provided in [1], the “foreign key” stored in first cell of
GridView1 (e.Row.Cells[0].Text)
is passed to
DefaultValue
property of only one
SelectParameter
(
SelectParameters[0]
) of SqlDataSource2:
Listing 1. Original solution on MSDN w/hardcoded Cells index
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e){
if (e.Row.RowType == DataControlRowType.DataRow)
{
SqlDataSource s = (SqlDataSource)e.Row.FindControl("SqlDataSource2");
s.SelectParameters[0].DefaultValue = e.Row.Cells[0].Text;
}
}
This should work in all practical versions of ASP.NET (2.0/3.5/4.0). However, the potential drawback of this solution rises from the fact that the foreign key value (for example, ID) could be omitted from visible fields set of
GridView1
control. Also, even in case this foreign key field is presented in
GridView1
, then there is potential inconvenience of hard-coded Cell index of
0
; generally, it can be not the first one in the field set and, also, its index could change dynamically during the data table editing operations or as a result of dynamically re-arranging table columns order.
Better solution
Better solution shown in the following Listing 2 effectively resolves all of those potential issues described above by using named
DataKeys
in
GridView1
control to be used as a "foreign keys" for second
DataSource
. In this particular example,
DataKey
“
Composer
” is added to
DataKeys
in GridView1 control (requires the line
DataKeyNames="Composer"
) to be passed to corresponding select parameter
s.SelectParameters[0].DefaultValue
of second
DataSource
named “
dsMusic
”.
Listing 2. Improved version using DataKeys
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) {
if (e.Row.RowType == DataControlRowType.DataRow)
{
AccessDataSource s = (AccessDataSource)e.Row.FindControl("dsMusic");
s.SelectParameters[0].DefaultValue = Convert.ToString(((GridView)sender).DataKeys[e.Row.RowIndex].Values["Composer"]);
}
}
Note: Listing 2 demonstrates the use of ASP.NET AccessDataSource
, but the concept/usage is pretty much identical to SqlDataSource
.
Sample Demo
Online Music Library with attached YouTube player [2-4] is implemented using the nested
GridView
techniques described above: click the image below to see the working demo:
Performance Improvement
Significant performance improvement could be achieved by enabling caching for nested
DataSource
s and using
FilterParameters
instead of
SelectParameters
. To do so:
- Set the nested
DataSource
attributes; FilterExpression="Composer ='{0}'" EnableCaching="True"
- Modify the event procedure in Listing 2 by replacing the line assigning
SelectParameters
with the following one:
s.FilterParameters[0].DefaultValue = Convert.ToString(((GridView)sender).DataKeys[e.Row.RowIndex].Values["Composer"]);
... and voila (that's it!)
References
- Walkthrough: Creating a Nested GridView Control[^]
- Music Library implemented as nested GridView controls [^]
- YouTube™ API for ASP.NET[^]
- YouTube™ Embedded Video Player: Extended API (C#)[^]