Add a Details button to each row in the Datagrid
.
When the user clicks the button, open a new browser window, obtain
the information from the server, and then display the detailed
information in a pop-up window. An example of the output that is
possible with this approach is shown in Figure 1-22
(sample DataGrid
) and Figure 1-23
(sample pop-up window output). As with the other recipes in this
book, we’ve implemented a complete application that
illustrates this approach. The form and code-behind for the page
containing the sample DataGrid
is shown in
Example 1-51 through Example 1-53, and the form and code-behind for the sample
pop-up window is shown in Example 1-54
through Example 1-56.
To implement this solution, create a DataGrid
in
the normal fashion, but add a link button column to display a Details
link. The idea is that when the user clicks the Details link within a
row of the DataGrid
, the browser opens a new
window and requests the appropriate page from the server. In the
context of our example that implements this solution, a book details
page is requested. From here on, the recipe’s
remaining steps are described in the context of our example because
we use techniques that you are likely to find helpful in implementing
your own application.
In our example, when the book details page is processed, a book ID is
extracted from the query string and is then used in the database
query to get the detailed data for the specific book, as shown in the
setupForm
method of Example 1-55
(VB) and Example 1-56 (C#).
When building a Details link in the .aspx
file,
an HTML anchor tag is placed in the ItemTemplate
for the column. (The purpose of the anchor tag is to request the
details page when the associated link button is clicked.) The
target
property of the HTML anchor is set to
"_blank
“, causing a new browser window to open
when the link is clicked.
The Page_Load
method in the code-behind is nearly
identical to that used in other recipes, with only one small change.
The line of code shown next is added to populate the
DataKeys
collection of the
DataGrid
with the primary key values for the rows
being displayed. This causes the DataGrid
to keep
track of the primary key value for each row without our having to
output the data in a hidden column. These values are needed later to
display the book details.
dgBooks.DataKeyField = "BookID" dgBooks.DataKeyField = "BookID";
The DataGrid
control’s
ItemDataBound
event is used to set the
href
value for the
“details” HTML anchors added to the
DataGrid
. Because this event is called
independently for every row in the DataGrid
, the
item type must be checked to see if this event applies for a given
data row.
When the event does apply to a data row, the first thing we must do is get the ID of the book being displayed in the row, as shown here:
bookID = CInt(dgBooks.DataKeys(e.Item.ItemIndex)) bookID = (int)(dgBooks.DataKeys[e.Item.ItemIndex]);
Next, we need to get a reference to the
“details” HTML anchor in the row.
Because ItemTemplates
were used and the anchor
controls in the templates were given IDs, we can accomplish this by
using the FindControl
method of the passed item.
If a standard BoundColumn
were used instead, the
data would have to be accessed using the cells collection (e.g.,
e.Item.Cells(1).controls(1)
would access the
anchor control in this example). Providing an ID and using
FindControl
eliminates the potential for broken
code if the columns are later reordered. Note that the control must
be cast to an HTMLAnchor
because the controls
collection is a collection of objects.
After obtaining a reference to the HTML anchor tag, we need to set
the href
property of the anchor to the name of the
details page. In addition, the URL needs to include
"BookID =
n
" where
n
is the ID of the book displayed in the
row. The resulting anchor tag in the DataGrid
for
BookID = 1
is shown here:
<a href="/ASPNetCookbook/VBExamples/BookDetails.aspx?BookID=1" id="dgBooks_ _ctl3_lnkDetails" target="_blank">
Tip
The ID is altered by ASP.NET to ensure all server controls have
unique IDs. ASP.NET maintains both the original ID and the unique ID,
so the original ID we provided with the
FindControl
method is handled correctly, sparing
us from having to figure out the unique ID or dealing with indexing
into items and cells.
Example 1-51. DataGrid with pop-up details window (.aspx)
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="CH01DatagridWithPopupDetailsVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH01DatagridWithPopupDetailsVB" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>DataGrid With Popup Details</title> <link rel="stylesheet" href="css/ASPNetCookbook.css"> </head> <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <form id="frmDatagrid" method="post" runat="server"> <table width="100%" cellpadding="0" cellspacing="0" border="0"> <tr> <td align="center"> <img src="images/ASPNETCookbookHeading_blue.gif"> </td> </tr> <tr> <td class="dividerLine"> <img src="images/spacer.gif" height="6" border="0"></td> </tr> </table> <table width="90%" align="center" border="0"> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center" class="PageHeading"> DataGrid With Popup Details (VB) </td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center"><asp:DataGrid
id="dgBooks"
runat="server"
BorderColor="000080"
BorderWidth="2px"
AutoGenerateColumns="False"
width="100%">
<HeaderStyle
HorizontalAlign="Center"
ForeColor="#FFFFFF"
BackColor="#000080"
Font-Bold=true
CssClass="TableHeader" />
<ItemStyle
BackColor="#FFFFE0"
cssClass="TableCellNormal" />
<AlternatingItemStyle
BackColor="#FFFFFF"
cssClass="TableCellAlternating" />
<Columns>
<asp:BoundColumn HeaderText="Title" DataField="Title" />
<asp:TemplateColumn ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<a id="lnkDetails" runat="server"
target="_blank">Details</a>
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:DataGrid>
</td> </tr> </table> </form> </body> </html>
Example 1-52. DataGrid with pop-up details window code-behind (.vb)
Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH01DatagridWithPopupDetailsVB.aspx.vb ' ' Description: This class provides the code behind for ' CH01DatagridWithPopupDetailsVB ' '***************************************************************************** Imports Microsoft.VisualBasic Imports System Imports System.Configuration Imports System.Data Imports System.Data.OleDb Imports System.Web.UI.HtmlControls Imports System.Web.UI.WebControls Namespace ASPNetCookbook.VBExamples Public Class CH01DatagridWithPopupDetailsVB Inherits System.Web.UI.Page 'controls on form Protected WithEvents dgBooks As System.Web.UI.WebControls.DataGrid '************************************************************************* ' ' ROUTINE: Page_Load ' ' DESCRIPTION: This routine provides the event handler for the page load ' event. It is responsible for initializing the controls ' on the page. '------------------------------------------------------------------------- Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load Dim dbConn As OleDbConnection Dim da As OleDbDataAdapter Dim ds As DataSet Dim strConnection As String Dim strSQL As String If (Not Page.IsPostBack) Then Try 'get the connection string from web.config and open a connection 'to the database strConnection = _ ConfigurationSettings.AppSettings("dbConnectionString") dbConn = New OleDb.OleDbConnection(strConnection) dbConn.Open( ) 'build the query string and get the data from the database strSQL = "SELECT BookID, Title " & _ "FROM Book " & _ "ORDER BY Title" da = New OleDbDataAdapter(strSQL, dbConn) ds = New DataSet da.Fill(ds) 'set the source of the data for the datagrid control and bind itdgBooks.DataKeyField = "BookID"
dgBooks.DataSource = ds dgBooks.DataBind( ) Finally 'cleanup If (Not IsNothing(dbConn)) Then dbConn.Close( ) End If End Try End If End Sub 'Page_Load '************************************************************************* ' ' ROUTINE: dgBooks_ItemDataBound ' ' DESCRIPTION: This routine is the event handler that is called for each ' item in the datagrid after a data bind occurs. It is ' responsible for setting the URL of the anchor tags to the ' page used to display the details for a book '-------------------------------------------------------------------------Private Sub dgBooks_ItemDataBound(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) _
Handles dgBooks.ItemDataBound
Const DETAIL_PAGE As String = "CH01BookDetailsVB.aspx"
Dim bookID As Integer
Dim anchor As HtmlAnchor
'check the type of item that was databound and only take action if it
'was a row in the datagrid
If ((e.Item.ItemType = ListItemType.Pager) Or _
(e.Item.ItemType = ListItemType.Header) Or _
(e.Item.ItemType = ListItemType.Footer)) Then
'do nothing
Else
'the item that was bound is an "Item", "AlternatingItem", "EditItem",
'"SelectedItem" or "Separator" (in other words a row)
bookID = CInt(dgBooks.DataKeys(e.Item.ItemIndex))
'get the anchor tag in the row
'NOTE: This can be done by using the FindControl method of the passed
' item because ItemTemplates were used and the anchor controls in
' the templates where given IDs. If a standard BoundColumn was
' used, the data would have to be accessed using the cells
' collection (e.g. e.Item.Cells(1).controls(1) would access the
' anchor control in this example.
anchor = CType(e.Item.FindControl("lnkDetails"), _
HtmlAnchor)
'set the URL of the anchor tag to the page used to display the book
'details passing the ID of the book in the querystring
anchor.HRef = DETAIL_PAGE & "?BookID=" & bookID.ToString( )
End If
End Sub 'dgBooks_ItemDataBound
End Class 'CH01DatagridWithPopupDetailsVB End Namespace
Example 1-53. DataGrid with pop-up details window code-behind (.cs)
//---------------------------------------------------------------------------- // // Module Name: CH01DatagridWithPopupDetailsCS.aspx.cs // // Description: This class provides the code behind for // CH01DatagridWithPopupDetailsCS.aspx // //**************************************************************************** using System; using System.Configuration; using System.Data; using System.Data.OleDb; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; namespace ASPNetCookbook.CSExamples { public class CH01DatagridWithPopupDetailsCS : System.Web.UI.Page { // controls on form protected System.Web.UI.WebControls.DataGrid dgBooks; //************************************************************************ // // ROUTINE: Page_Load // // DESCRIPTION: This routine provides the event handler for the page // load event. It is responsible for initializing the // controls on the page. // //------------------------------------------------------------------------ private void Page_Load(object sender, System.EventArgs e) { OleDbConnection dbConn = null; OleDbDataAdapter da = null; DataSet ds = null; String strConnection = null; String strSQL =null; // wire the item data bound event this.dgBooks.ItemDataBound += new DataGridItemEventHandler(this.dgBooks_ItemDataBound); if (!Page.IsPostBack) { try { // get the connection string from web.config and open a connection // to the database strConnection = ConfigurationSettings.AppSettings["dbConnectionString"]; dbConn = new OleDbConnection(strConnection); dbConn.Open( ); // build the query string and get the data from the database strSQL = "SELECT BookID, Title " + "FROM Book " + "ORDER BY Title"; da = new OleDbDataAdapter(strSQL, dbConn); ds = new DataSet( ); da.Fill(ds); // set the source of the data for the datagrid control and bind itdgBooks.DataKeyField = "BookID";
dgBooks.DataSource = ds; dgBooks.DataBind( ); } // try finally { // clean up if (dbConn != null) { dbConn.Close( ); } } // finally } } // Page_Load //************************************************************************ // // ROUTINE: dgBooks_ItemDataBound // // DESCRIPTION: This routine is the event handler that is called for each // item in the datagrid after a data bind occurs. It is // responsible for setting the URL of the anchor tags to the // page used to display the details for a book // //------------------------------------------------------------------------private void dgBooks_ItemDataBound(Object sender,
System.Web.UI.WebControls.DataGridItemEventArgs e)
{
const String DETAIL_PAGE = "CH01BookDetailsCS.aspx";
int bookID;
HtmlAnchor anchor = null;
// check the type of item that was databound and only take action if it
// was a row in the datagrid
if ((e.Item.ItemType == ListItemType.Pager) ||
(e.Item.ItemType == ListItemType.Header) ||
(e.Item.ItemType == ListItemType.Footer))
{
// do nothing
}
else
{
// the item that was bound is an "Item", "AlternatingItem",
// "EditItem", "SelectedItem" or "Separator" (in other words a row)
bookID = (int)(dgBooks.DataKeys[e.Item.ItemIndex]);
// get the anchor tag in the row
// NOTE: This can be done by using the FindControl method of the
// passeditem because ItemTemplates were used and the anchor
// controls in the templates where given IDs. If a standard
// BoundColumn was used, the data would have to be accessed
// using the cells collection (e.g. e.Item.Cells(1).controls(1)
// would access the anchor control in this example.
anchor = (HtmlAnchor)(e.Item.FindControl("lnkDetails"));
// set the URL of the anchor tag to the page used to display the book
// details passing the ID of the book in the querystring
anchor.HRef = DETAIL_PAGE + "?BookID=" + bookID.ToString( );
}
} // dgBooks_ItemDataBound
} // CH01DatagridWithPopupDetailsCS }
Example 1-54. Pop-up detail page (.aspx)
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="CH01BookDetailsVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH01BookDetailsVB" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Book Details</title> <meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0"> <meta name="CODE_LANGUAGE" content="Visual Basic 7.0"> <meta name=vs_defaultClientScript content="JavaScript"> <meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5"> <link rel="stylesheet" href="css/ASPNetCookbook.css"> </head> <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <form id="frmDatagrid" method="post" runat="server"> <table width="100%" cellpadding="0" cellspacing="0" border="0"> <tr> <td align="center"> <img src="images/ASPNETCookbookHeading_blue.gif"> </td> </tr> <tr> <td class="dividerLine"> <img src="images/spacer.gif" height="6" border="0"></td> </tr> </table> <table width="90%" align="center" border="0"> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center" class="PageHeading"> Book Details (VB) </td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center"> <!-- Put book details here --> <table width="600" border="0"> <tr> <td rowspan="6" align="center" width="250"> <img id="imgBook" runat="server"></td> <td class="TableCellNormal" width="150">Title: </td> <td id="bookTitle" runat="server" class="TableCellNormal" width="325"></td> </tr> <tr> <td class="TableCellNormal">ISBN: </td> <td id="isbn" runat="server" class="TableCellNormal"></td> </tr> <tr> <td class="TableCellNormal">Publisher: </td> <td id="publisher" runat="server" class="TableCellNormal"></td> </tr> <tr> <td class="TableCellNormal">Publish Date: </td> <td id="publishDate" runat="server" class="TableCellNormal"></td> </tr> <tr> <td class="TableCellNormal">List Price: </td> <td id="listPrice" runat="server" class="TableCellNormal"></td> </tr> <tr> <td class="TableCellNormal">Discounted Price: </td> <td id="discountedPrice" runat="server" class="TableCellNormal"></td> </tr> </table> </td> </tr> </table> </form> </body> </html>
Example 1-55. Pop-up detail page code-behind (.vb)
Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH01BookDetailsVB.aspx.vb ' ' Description: This class provides the code behind for ' CH01BookDetailsVB.aspx ' '***************************************************************************** Imports Microsoft.VisualBasic Imports System Imports System.Configuration Imports System.Data Imports System.Data.OleDb Namespace ASPNetCookbook.VBExamples Public Class CH01BookDetailsVB Inherits System.Web.UI.Page 'controls on form Protected imgBook As System.Web.UI.HtmlControls.HtmlImage Protected bookTitle As System.Web.UI.HtmlControls.HtmlTableCell Protected isbn As System.Web.UI.HtmlControls.HtmlTableCell Protected publisher As System.Web.UI.HtmlControls.HtmlTableCell Protected publishDate As System.Web.UI.HtmlControls.HtmlTableCell Protected listPrice As System.Web.UI.HtmlControls.HtmlTableCell Protected discountedPrice As System.Web.UI.HtmlControls.HtmlTableCell '************************************************************************* ' ' ROUTINE: Page_Load ' ' DESCRIPTION: This routine provides the event handler for the page load ' event. It is responsible for initializing the controls ' on the page. '------------------------------------------------------------------------- Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load Dim dbConn As OleDbConnection Dim dCmd As OleDbCommand Dim dReader As OleDbDataReader Dim strConnection As String Dim strSQL As String Dim bookID As String If (Not Page.IsPostBack) Then Try'get the book ID from the querystring in the URL
If (IsNothing(Request.QueryString.Item("BookID"))) Then
'production code needs to handle the page request without the needed
'information in the querystring here
Else
bookID = Request.QueryString.Item("BookID").ToString( )
'get the connection string from web.config and open a connection
'to the database
strConnection = _
ConfigurationSettings.AppSettings("dbConnectionString")
dbConn = New OleDbConnection(strConnection)
dbConn.Open( )
'build the query string and get the data from the database
strSQL = "SELECT Title, ISBN, Publisher, PublishDate, " & _
"ListPrice, DiscountedPrice, ImageFilename " & _
"FROM Book " & _
"WHERE BookID=?"
dCmd = New OleDbCommand(strSQL, dbConn)
dCmd.Parameters.Add(New OleDbParameter("BookID", bookID))
dReader = dCmd.ExecuteReader( )
If (dReader.Read) Then
'set the data in the individual controls on the page
imgBook.Src = "images/books/" & _
dReader.Item("ImageFilename").ToString( )
bookTitle.InnerText = dReader.Item("Title").ToString( )
isbn.InnerText = dReader.Item("ISBN").ToString( )
publisher.InnerText = dReader.Item("Publisher").ToString( )
publishDate.InnerText = Format(dReader.Item("PublishDate"), _
"MMM dd, yyyy")
listPrice.InnerText = Format(dReader.Item("ListPrice"), _
"C2")
discountedPrice.InnerText = Format(dReader.Item("DiscountedPrice"), _
"C2")
End If
End If Finally 'cleanup If (Not IsNothing(dReader)) Then dReader.Close( ) End If If (Not IsNothing(dbConn)) Then dbConn.Close( ) End If End Try End If End Sub 'Page_Load End Class 'CH01BookDetailsVB End Namespace
Example 1-56. Pop-up detail page code-behind (.cs)
//---------------------------------------------------------------------------- // // Module Name: CH01BookDetailsCS.aspx.cs // // Description: This class provides the code behind for // CH01BookDetailsCS.aspx // //**************************************************************************** using System; using System.Configuration; using System.Data; using System.Data.OleDb; namespace ASPNetCookbook.CSExamples { public class CH01BookDetailsCS : System.Web.UI.Page { // controls on form protected System.Web.UI.HtmlControls.HtmlImage imgBook; protected System.Web.UI.HtmlControls.HtmlTableCell bookTitle ; protected System.Web.UI.HtmlControls.HtmlTableCell isbn; protected System.Web.UI.HtmlControls.HtmlTableCell publisher; protected System.Web.UI.HtmlControls.HtmlTableCell publishDate; protected System.Web.UI.HtmlControls.HtmlTableCell listPrice; protected System.Web.UI.HtmlControls.HtmlTableCell discountedPrice; //************************************************************************ // // ROUTINE: Page_Load // // DESCRIPTION: This routine provides the event handler for the page // load event. It is responsible for initializing the // controls on the page. // //------------------------------------------------------------------------ private void Page_Load(object sender, System.EventArgs e) { OleDbConnection dbConn = null; OleDbCommand dCmd = null; OleDbDataReader dReader = null; String strConnection = null; String strSQL = null; String bookID = null; DateTime pubDate; Decimal price; if (!Page.IsPostBack) { try {// get the book ID from the querystring in the URL
if (Request.QueryString["BookID"] == null)
{
// production code needs to handle the page request without the
// needed information in the querystring here
}
else
{
bookID = Request.QueryString["BookID"].ToString( );
// get the connection string from web.config and open a connection
// to the database
strConnection =
ConfigurationSettings.AppSettings["dbConnectionString"];
dbConn = new OleDbConnection(strConnection);
dbConn.Open( );
// build the query string and get the data from the database
strSQL = "SELECT Title, ISBN, Publisher, PublishDate, " +
"ListPrice, DiscountedPrice, ImageFilename " +
"FROM Book " +
"WHERE BookID=?";
dCmd = new OleDbCommand(strSQL, dbConn);
dCmd.Parameters.Add(new OleDbParameter("BookID", bookID));
dReader = dCmd.ExecuteReader( );
if (dReader.Read( ))
{
// set the data in the individual controls on the page
imgBook.Src = "images/books/" +
dReader["ImageFilename"].ToString( );
bookTitle.InnerText = dReader["Title"].ToString( );
isbn.InnerText = dReader["ISBN"].ToString( );
publisher.InnerText = dReader["Publisher"].ToString( );
pubDate = (DateTime)dReader["PublishDate"];
publishDate.InnerText = pubDate.ToString("MMM dd, yyyy");
price = (Decimal)dReader["ListPrice"];
listPrice.InnerText = price.ToString("C2");
price = (Decimal)dReader["DiscountedPrice"];
discountedPrice.InnerText = price.ToString("C2");
}
}
} // try finally { // clean up if (dReader != null) { dReader.Close( ); } if (dbConn != null) { dbConn.Close( ); } } // finally } } // Page_Load } // CH01BookDetailsCS }
Get ASP.NET Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.