You are implementing a DataGrid
that
requires selection of a row, but you do
not want to have a Select button in every row of your
DataGrid
. What you really want is to allow the
user to click anywhere within a row, like in a classic Windows
application.
To every row in the DataGrid
add a hidden Select
button along with an onclick
event that performs
the same action as if the hidden Select button were clicked.
Add a hidden
ButtonColumn
to theDataGrid
.Set the
ButtonType
attribute to "LinkButton
" so that a hidden hyperlinked Select button is rendered in every row.In the
ItemDataBound
event, add anonclick
event to theDataGrid
row that performs the same action as clicking the hidden Select button.
The approach produces output like that shown in Figure 1-20. Example 1-45 through
Example 1-47 show the .aspx
and
code-behind files for the application that produces this result.
To allow selection of a row of data simply by clicking on it, you
create a DataGrid
in the usual fashion but add a
hidden ButtonColumn
. The
ButtonType
attribute is set to
"LinkButton
“, and the
CommandName
attribute is set to
"Select
“. This causes the
DataGrid
to be rendered with a hidden hyperlinked
Select button in every row.
<Columns><asp:ButtonColumn ButtonType="LinkButton"
Visible="False"
CommandName="Select" />
... </Columns>
In the code-behind, the DataGrid
control’s ItemDataBound
event
handler (dgProblems_ItemDataBound
) is used to
expand the functionality of the hidden Select button to encompass the
entire row. This method is called for every row of the
DataGrid
, including the header and footer, so the
item type must be checked to see if this event applies to a given
data row.
When the event applies to a data row, the first thing you must do is
get a reference to the hidden Select button in the row. The
LINK_BUTTON_COLUMN
and
LINK_BUTTON_CONTROL
constants are used to avoid
so-called “magic numbers”
(hardcoded numbers that seem to appear out of nowhere in the code)
and to make the code more maintainable.
Next, some client-side JavaScript is added to a
row’s hidden hyperlinked Select button. Its sole
purpose is to handle the onclick
event for the row
in the DataGrid
that has just been data bound and
to perform a call to _ _doPostBack
. The JavaScript
is added to the DataGrid
row’s
Attributes
collection using the
Add
method, whose parameters are the name of the
event we want to add to the control and the name of the function
(along with its parameters) that is to be executed when the event
occurs.
The Page
’s
GetPostBackClientHyperlink
method is used to get
the name of the client-side function created for the hidden Select
button in the row being processed. It returns the name of the event
method along with the required parameters. For the first row in our
DataGrid
, for example, the
GetPostBackClientHyperlink
method returns
javascript:_ _doPostBack('dgProblems:_ctl2:_ctl0','')
.
Effectively, this adds an onclick
event to all the
table rows, which causes the method _ _doPostBack
to be called anytime the user clicks on a data row in the grid.
Because this onclick
event is identical to the
event created for the hidden Select button in the row, the
postback
is processed as a select event, thereby
setting the SelectedIndex
of the
DataGrid
to the clicked row.
Warning
Be aware that the selection of a row using this method requires a round trip to the server to perform the selection.
This example shows the use of Add, Edit, and Delete buttons below the
DataGrid
, which is typical of a scenario where a
row is selected and then a desired action is performed on it. The
methods for the Add, Edit, and Delete events were included in this
recipe but were left empty to keep the code down to a reasonable
size.
Example 1-45. DataGrid allowing selection anywhere (.aspx)
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="CH01DatagridWithSelectionAnywhereVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH01DatagridWithSelectionAnywhereVB" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>DataGrid With Selection Anywhere</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 Selection Anywhere (VB) </td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center"> <!-- The first column defined in the Columns element is a hidden link button to provide the ability to make clicking anywhere in the row the same as clicking the link button. See the dgProblems_ItemDataBound method in the code behind page --><asp:DataGrid
id="dgProblems"
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" />
<SelectedItemStyle
BackColor="#cccccc"
cssClass="TableCellAlternating" />
<Columns>
<asp:ButtonColumn ButtonType="LinkButton"
Visible="False"
CommandName="Select" />
<asp:BoundColumn HeaderText="Title"
DataField="Title"
ItemStyle-HorizontalAlign="Left" />
<asp:BoundColumn HeaderText="Publish Date"
DataField="PublishDate"
ItemStyle-HorizontalAlign="Center"
DataFormatString="{0:MMM dd, yyyy}"/>
<asp:BoundColumn HeaderText="List Price"
DataField="ListPrice"
ItemStyle-HorizontalAlign="Center"
DataFormatString="{0:C2}"/>
</Columns>
</asp:DataGrid>
</td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center"> <table width="100%"> <tr> <td width="18%"> </td> <td width="15%" align="center"> <asp:ImageButton id="btnAdd" runat="server" ImageUrl="images/buttons/button_add.gif" /></td> <td width="10%"> </td> <td width="15%" align="center"> <asp:ImageButton id="btnEdit" runat="server" ImageUrl="images/buttons/button_edit.gif" /></td> <td width="10%"> </td> <td width="15%" align="center"> <asp:ImageButton id="btnDelete" runat="server" ImageUrl="images/buttons/button_delete.gif" /></td> <td width="17%"> </td> </tr> </table> </td> </tr> </table> </form> </body> </html>
Example 1-46. DataGrid allowing selection anywhere code-behind (.vb)
Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH01DatagridWithSelectionAnywhereVB.aspx.vb ' ' Description: This class provides the code behind for ' CH01DatagridWithSelectionAnywhereVB ' '***************************************************************************** Imports Microsoft.VisualBasic Imports System.Configuration Imports System.Data Imports System.Data.OleDb Imports System.Web.UI.WebControls Namespace ASPNetCookbook.VBExamples Public Class CH01DatagridWithSelectionAnywhereVB Inherits System.Web.UI.Page 'controls on form Protected WithEvents btnAdd As System.Web.UI.WebControls.ImageButton Protected WithEvents btnEdit As System.Web.UI.WebControls.ImageButton Protected WithEvents btnDelete As System.Web.UI.WebControls.ImageButton Protected WithEvents dgProblems 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 If (Not Page.IsPostBack) Then bindData( ) End If End Sub 'Page_Load '************************************************************************* ' ' ROUTINE: dgProblems_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 making each row a link button to ' allow clicking anywhere to select a row. '-------------------------------------------------------------------------Private Sub dgProblems_ItemDataBound(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) _
Handles dgProblems.ItemDataBound
'datagrid column containing link button defined on ASPX page
Const LINK_BUTTON_COLUMN As Integer = 0
'index of link button control in the link button column
Const LINK_BUTTON_CONTROL As Integer = 0
Dim button As LinkButton
'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) so get a
'reference to the link button column defined in the Columns property
'of the datagrid (in the aspx page) and add an event handler for the
'the onclick event for this entire row. This will make clicking
'anywhere in the row select the row.
'NOTE: This is tightly coupled to the definition of the bound columns
' in the aspx page.
button = _
CType(e.Item.Cells(LINK_BUTTON_COLUMN).Controls(LINK_BUTTON_CONTROL), _
LinkButton)
e.Item.Attributes.Add("onclick", _
Page.GetPostBackClientHyperlink(button, ""))
End If
End Sub 'dgProblems_ItemDataBound
'************************************************************************* ' ' ROUTINE: btnAdd_Click ' ' DESCRIPTION: This routine is the event handler that is called when ' the Add button is clicked. '------------------------------------------------------------------------- Private Sub btnAdd_Click(ByVal sender As Object, _ ByVal e As System.Web.UI.ImageClickEventArgs) _ Handles btnAdd.Click 'place code here to perform Add operations End Sub 'btnAdd_Click '************************************************************************* ' ' ROUTINE: btnEdit_Click ' ' DESCRIPTION: This routine is the event handler that is called when ' the Edit button is clicked. '------------------------------------------------------------------------- Private Sub btnEdit_Click(ByVal sender As Object, _ ByVal e As System.Web.UI.ImageClickEventArgs) _ Handles btnEdit.Click 'place code here to perform Edit operations End Sub 'btnEdit_Click '************************************************************************* ' ' ROUTINE: btnDelete_Click ' ' DESCRIPTION: This routine is the event handler that is called when ' the Delete button is clicked. '------------------------------------------------------------------------- Private Sub btnDelete_Click(ByVal sender As Object, _ ByVal e As System.Web.UI.ImageClickEventArgs) _ Handles btnDelete.Click 'place code here to perform Delete operations End Sub 'btnDelete_Click '************************************************************************* ' ' ROUTINE: bindData ' ' DESCRIPTION: This routine queries the database for the data to ' displayed and binds it to the datagrid ' '------------------------------------------------------------------------- Private Sub bindData( ) Dim dbConn As OleDbConnection Dim dCmd As OleDbCommand Dim dReader As OleDbDataReader Dim strConnection As String Dim strSQL As String 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 Title, PublishDate, ListPrice " & _ "FROM Book " & _ "ORDER BY Title" dCmd = New OleDbCommand(strSQL, dbConn) dReader = dCmd.ExecuteReader(CommandBehavior.Default) 'set the source of the data for the datagrid control and bind it dgProblems.DataSource = dReader dgProblems.DataBind( ) 'select first item in the datagrid dgProblems.SelectedIndex = 0 Finally 'cleanup If (Not IsNothing(dReader)) Then dReader.Close( ) End If If (Not IsNothing(dbConn)) Then dbConn.Close( ) End If End Try End Sub 'bindData End Class 'CH01DatagridWithSelectionAnywhereVB End Namespace
Example 1-47. DataGrid allowing selection anywhere code-behind (.cs)
//---------------------------------------------------------------------------- // // Module Name: CH01DatagridWithSelectionAnywhereCS.aspx.cs // // Description: This class provides the code behind for // CH01DatagridWithSelectionAnywhereCS.aspx // //**************************************************************************** using System; using System.Configuration; using System.Data; using System.Data.OleDb; using System.Web.UI; using System.Web.UI.WebControls; namespace ASPNetCookbook.CSExamples { public class CH01DatagridWithSelectionAnywhereCS : System.Web.UI.Page { // controls on form protected System.Web.UI.WebControls.ImageButton btnAdd; protected System.Web.UI.WebControls.ImageButton btnEdit; protected System.Web.UI.WebControls.ImageButton btnDelete; protected System.Web.UI.WebControls.DataGrid dgProblems; //************************************************************************ // // 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) { // wire the item data bound and button events this.dgProblems.ItemDataBound += new DataGridItemEventHandler(this.dgProblems_ItemDataBound); this.btnAdd.Click += new ImageClickEventHandler(this.btnAdd_Click); this.btnEdit.Click += new ImageClickEventHandler(this.btnEdit_Click); this.btnDelete.Click += new ImageClickEventHandler(this.btnDelete_Click); if (!Page.IsPostBack) { bindData( ); } } // Page_Load //************************************************************************ // // ROUTINE: dgProblems_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 making each row a link button to // allow clicking anywhere to select a row. //------------------------------------------------------------------------private void dgProblems_ItemDataBound(Object sender,
System.Web.UI.WebControls.DataGridItemEventArgs e)
{
// datagrid column containing link button defined on ASPX page
const int LINK_BUTTON_COLUMN = 0;
// index of link button control in the link button column
const int LINK_BUTTON_CONTROL = 0;
LinkButton button = 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)
// so get a reference to the link button column defined in the
// Columns property of the datagrid (in the aspx page) and add an
// event handler for the the onclick event for this entire row. This
// will make clicking anywhere in the row select the row.
// NOTE: This is tightly coupled to the definition of the bound
// columns in the aspx page.
button =
(LinkButton)(e.Item.Cells[LINK_BUTTON_COLUMN].Controls[LINK_BUTTON_CONTROL]);
e.Item.Attributes.Add("onclick",
Page.GetPostBackClientHyperlink(button, ""));
}
} // dgProblems_ItemDataBound
//************************************************************************ // // ROUTINE: btnAdd_Click // // DESCRIPTION: This routine is the event handler that is called when // the Add button is clicked. //------------------------------------------------------------------------ private void btnAdd_Click(Object sender, System.Web.UI.ImageClickEventArgs e) { // place code here to perform Add operations } // btnAdd_Click //************************************************************************ // // ROUTINE: btnEdit_Click // // DESCRIPTION: This routine is the event handler that is called when // the Edit button is clicked. //------------------------------------------------------------------------ private void btnEdit_Click(Object sender, System.Web.UI.ImageClickEventArgs e) { // place code here to perform Edit operations } // btnEdit_Click //************************************************************************ // // ROUTINE: btnDelete_Click // // DESCRIPTION: This routine is the event handler that is called when // the Delete button is clicked. //------------------------------------------------------------------------ private void btnDelete_Click(Object sender, System.Web.UI.ImageClickEventArgs e) { // place code here to perform Delete operations } // btnDelete_Click //************************************************************************ // // ROUTINE: bindData // // DESCRIPTION: This routine queries the database for the data to // displayed and binds it to the repeater //------------------------------------------------------------------------ private void bindData( ) { OleDbConnection dbConn = null; OleDbCommand dCmd = null; OleDbDataReader dReader = null; String strConnection = null; String strSQL =null; 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 Title, PublishDate, ListPrice " + "FROM Book " + "ORDER BY Title"; dCmd = new OleDbCommand(strSQL, dbConn); dReader = dCmd.ExecuteReader(CommandBehavior.Default); // set the source of the data for the datagrid control and bind it dgProblems.DataSource = dReader; dgProblems.DataBind( ); // select first item in the datagrid dgProblems.SelectedIndex = 0; } // try finally { // clean up if (dReader != null) { dReader.Close( ); } if (dbConn != null) { dbConn.Close( ); } } // finally } // bindData } // CH01DatagridWithSelectionAnywhereCS }
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.