Untitled 1
Creating Master Detail Pages using GridView
Introduction
Many months ago I wrote
an article title that demonstrated the use of DataList and DataGrid controls
to create master detail pages. ASP.NET 2.0 introduced GridView control
supersedes the older DataGrid control and adds many enhancements. In this
article I am going to show how master detail pages can be developed using
GridView control and SQL Data Source control.
Creating the web site
In order to begin developing our sample you need to create a new ASP.NET web
site in Visual Studio. Also, ensure that you have access to Northwind database
of SQL Server 2005.
Configuring SQL Data Source Control Supplying Master Records
Now drag and drop an SQL data source control on the default web form.
Configure it to select CustomerID, CompanyName, ContactName and Country columns
from the Customers table of Northwind database.

Creating Parent GridView
Next, drag and drop a GridView control on the web form. Set its DataSourceID
property to SqlDataSource1 (the one that we just configures) and DataKeyNames
property to CustomerID. Add two TemplateField columns to the GridView.

Design the second template field as shown below:

The second template field consists of a Button control. Set Text property of
the Button control to Show and CommandText property to Show. We will use the
CommandText property later in our code.
Now design the first TemplateField as shown below:

The ItemTemplate region consists of two Label controls, one GridView control
and one SQL data source control. Open the data bindings editor of the first
Label control and bind its Text property with CustomerID column.

Similarly bind the Text property of other label to CompanyName column.
Configuring SQL Data Source Control Supplying Detail Records
Now comes the important part viz. configure the SQL data source control that
supplies detail records. Remember that this SDS must be placed inside the
ItemTemplate and not on the web form. This way each row can fetch required
detail records. Configure this SDS as shown below:

Notice the SELECT query carefully. We fetch all orders from Orders table for
a specific CustomerID. It contains a parameter @CustoemrID that we will be
supplying via code. Set the parameter source for this parameter to None in the
final dialog of the SDS configuration wizard.

This completes configuration of the second SDS.
Creating Child GridView
Now select the GridView control that we placed inside the template field and
set its DataSourceID property to SqlDataSource2 i.e. the SDS inside the template
field. Add three BoundFields to the GridView as shown in the following figure:
Set their HeaderText property to Customer ID, Company Name and Contact Name
respectively. Similarly, set their DataField property to CustomerID, CompanyName
and ContactName respectively.
This completes the design part of our sample. Let's add some code that makes
our sample live.
Handling RowDataBound Event
Recollect that we have added a template field to the parent GridView that
contains a Button control. Later in our code we need to somehow identify that
Button from which row was clicked by the user. We achieve this by setting
CommandArgument property of the Button from each row to the row number. To set
this property we need to handle RowDataBound event of the GridView. The
RowDataBound event is raised when each and every row of the GridView including
header and footer is data bound. The following piece of code shows the
RowDataBound event handler of the GridView.
private int index = 0;
protected void GridView1_RowDataBound(object sender,
GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
Button b = (Button)e.Row.Cells[1].FindControl("Button1");
b.CommandArgument = index.ToString();
index=index+1;
}
}
The code declares a class level variable called index that keeps counter of
row number. The RowDataBound event handler first checks the RowType of the row
being data bound. This way we execute our code only for rows and not for header
and footer. We get hold of the button from each row using FindControl method of
second row cell (indexing starts from zero). We then set CommandArgument
property of the button to the row index.
Handling RowCommand Event
Now comes the final task. When users click on the Show button we should show
detail records belonging to the current master row. This is accomplished by
handling RowCommand event of the GridView as shown below:
protected void GridView1_RowCommand(object sender,
GridViewCommandEventArgs e)
{
if (e.CommandName == "Show")
{
Button b = (Button)GridView1.Rows[int.Parse
(e.CommandArgument.ToString())].Cells[1].
FindControl("Button1");
if (b.Text == "Show")
{
string custid = GridView1.DataKeys[int.Parse
(e.CommandArgument.ToString())].Value.ToString();
SqlDataSource sds = (SqlDataSource)GridView1.
Rows[int.Parse(e.CommandArgument.ToString())].
FindControl("SqlDataSource2");
GridView gv = (GridView)GridView1.Rows[int.Parse
(e.CommandArgument.ToString())].FindControl("GridView2");
sds.SelectParameters[0].DefaultValue = custid;
gv.Visible = true;
b.Text = "Hide";
}
else
{
GridView gv = (GridView)GridView1.Rows[int.Parse
(e.CommandArgument.ToString())].FindControl("GridView2");
gv.Visible = false;
b.Text = "Show";
}
}
}
The code checks the CommandName property of GridViewCommandEventArgs object
supplied to the event handler. This property will be Show when user clicks on
the Show button. The code then retrieves reference to the button that was
clicked. If the Text property of the button reads Show we retrieve CustomerID
for that row from DataKeys collection. The @CustomerID parameter of SQL data
source control is then supplied. Then the Visible property of details GridView
is set to true. Finally, Text property of the Button is changed to Hide.
The code in the "else" block simply hides the detail GridView and sets the
Text property of Button to Show.
That's it! We just completed developing a master detail page. Run the web
form and you should see something similar to the following figure:

Notice that you can hide or show the detail grid for individual master rows.
This is handy and often desired if your master grid contains many records.