Recipe 1.7 Adding Next /Previous Navigation to a DataGrid 1.7.1 Problem You need to display data from a database in a table, but the database has more rows than can fit on a single page so you want to use next/previous buttons for navigation. 1.7.2 Solution Use a DataGrid control, enable its built-in pagination features, and then bind the data to it. Add a DataGrid control to the .aspx file, and use its AllowPaging and other related attributes to enable pagination. In the code-behind class for the page, use the .NET language of your choice to: -
Create a routine that binds a DataSet to the DataGrid in the usual fashion. -
Create an event handler that performs the page navigation ”for example, one that handles the PageIndexChanged event for the DataGrid ”and rebinds the data. Figure 1-6 shows the appearance of a typical DataGrid within a browser with next/previous navigation. Example 1-17 through Example 1-19 show the .aspx and code-behind files for an application that produces this result. Figure 1-6. DataGrid with next/previous navigation output 1.7.3 Discussion The DataGrid control includes the ability to perform pagination of the data that is displayed in the grid, and using the built-in pagination requires very little code. Pagination is enabled and configured by the attributes of the DataGrid element: AllowPaging="True" PageSize="5" PagerStyle-Mode="NextPrev" PagerStyle-Position="Bottom" PagerStyle-HorizontalAlign="Center" PagerStyle-NextPageText="Next" PagerStyle-PrevPageText="Prev"> Setting the AllowPaging attribute to True enables paging for the DataGrid , and the PageSize attribute defines the number of rows that will be displayed in a single page. Setting the PageStyle-Mode attribute to NextPrev enables the output of the Next / Prev controls (see Recipe 1.9 for other uses of this attribute). The remaining attributes define how the pagination controls look. PageStyle-Position defines the location of the Next / Prev controls. Valid values include Bottom , Top , and TopAndBottom . PagerStyle-HorizontalAlign defines the horizontal positioning of the Next / Prev controls. Valid values include Left , Center , Right , and NotSet . NotSet is effectively the same as Left because Left is the default. PagerStyle-NextPageText defines the text to output for the next page navigation control, and PagerStyle-PrevPageText defines the text to output for the previous page navigation. | The PagerStyle-NextPageText and PagerStyle-PrevPageText attribute values can include HTML to format the text of the controls. Virtually any HTML can be used, including image tags. If you change the values of the two text attributes, the Next / Prev controls will be output, as shown in Figure 1-7. PagerStyle-NextPageText= "<img src='images/buttons/button_next.gif' border='0'>" PagerStyle-PrevPageText= "<img src='images/buttons/button_prev.gif' border='0'>"> | | Figure 1-7. DataGrid output using image tags for next/previous controls The bindData routine, shown in the code-behind in Example 1-18 (VB) and Example 1-19 (C#), performs the data binding. This routine provides the typical binding of a dataset to the DataGrid . No additional code is required in this routine to support the default pagination. The dgBooks_PageIndexChanged event handler provides the code required to perform the page navigation. The new page number to display is passed in the event arguments ( e ). The CurrentPageIndex property of the DataGrid must be set to the passed value, and the data must be rebound to the DataGrid . | The default pagination code shown in this recipe can be very inefficient when used with data containing a large number of rows. By default, all of the data for a query is returned and used to populate the DataSet . When the query returns a relatively small set of data (less than 100 rows and a small number of columns ), the pagination shown in this recipe is adequate for most applications. If your query returns a million rows, the performance of your application will be unacceptable. See Recipe 1.10 for a more efficient approach to the pagination of large datasets. | | 1.7.4 See Also Recipe 1.8, Recipe 1.9, and Recipe 1.10 for other examples of pagination Event Handlers VB and C# connect event handlers to events in very different ways. VB requires two additions to your code to handle an event. First, the control that has events to handle must be declared in the code-behind class using the WithEvents keyword, as shown here: Protected WithEvents dgBooks As DataGrid Second, the method that will be used to handle an event must have the Handles keyword added to the end of the method and include the control and event to be handled. This informs the compiler to add the code required to "wire" the event to the method. Private Sub dgBooks_PageIndexChanged(ByVal source As Object, ByVal e As DataGridPageChangedEventArgs) _ Handles dgBooks.PageIndexChanged In C#, events are connected to methods by explicitly creating a new event handler of the required type and "wiring" it to the desired control's event: this.dgBooks.PageIndexChanged += new DataGridPageChangedEventHandler (this.dgBooks_PageIndexChanged); In both VB and C# one method can be used to handle multiple events. This is useful when a page contains multiple buttons for the same action, such as a set of next/previous buttons at the top and bottom of a grid. This is accomplished in VB by listing the events that are to be handled after the Handles keyword: Private Sub btnNext_ServerClick(ByVal sender As Object, _ ByVal e As ImageClickEventArgs) _ Handles btnNext1.ServerClick, btnNext2.ServerClick In C#, using a single method to handle two events is done as shown here: this.btnNext.ServerClick += new ImageClickEventHandler(this.btnNext1_ServerClick); this.btnNext.ServerClick += new ImageClickEventHandler(this.btnNext2_ServerClick); | Example 1-17. DataGrid with next/previous navigation (.aspx) <%@ Page Language="vb" AutoEventWireup="false" Codebehind="CH01DatagridWithNextPrevNavVB1.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH01DatagridWithNextPrevNavVB1" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Datagrid With Text For Next/Prev Navigation</title> <link rel="stylesheet" href="css/ASPNetCookbook.css"> </head> <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <form id="frmData" 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 Using Text For Next/Previous Navigation (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%" AllowPaging="True" PageSize="5" PagerStyle-Mode="NextPrev" PagerStyle-Position="Bottom" PagerStyle-HorizontalAlign="Center" PagerStyle-NextPageText="Next" PagerStyle-PrevPageText="Prev"> <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:BoundColumn HeaderText="ISBN" DataField="ISBN" ItemStyle-HorizontalAlign="Center" /> <asp:BoundColumn HeaderText="Publisher" DataField="Publisher" ItemStyle-HorizontalAlign="Center" /> </Columns> </asp:DataGrid> </td> </tr> </table> </form> </body> </html> Example 1-18. DataGrid with next/previous navigation code-behind (.vb) Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH01DatagridWithNextPrevNavVB1.aspx.vb ' ' Description: This class provides the code behind for ' CH01DatagridWithNextPrevNavVB1.aspx ' '***************************************************************************** Imports Microsoft.VisualBasic Imports System.Configuration Imports System.Data Imports System.Data.OleDb Namespace ASPNetCookbook.VBExamples Public Class CH01DatagridWithNextPrevNavVB1 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 If (Not Page.IsPostBack) Then bindData( ) End If End Sub 'Page_Load '************************************************************************* ' ' ROUTINE: dgCustomers_PageIndexChanged ' ' DESCRIPTION: This routine provides the event handler for the page ' index changed event of the datagrid. It is responsible ' for setting the page index from the passed arguments and ' rebinding the data. '------------------------------------------------------------------------- Private Sub dgBooks_PageIndexChanged(ByVal source As Object, _ ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) _ Handles dgBooks.PageIndexChanged 'set new page index and rebind the data dgBooks.CurrentPageIndex = e.NewPageIndex bindData( ) End Sub 'dgCustomers_PageIndexChanged '************************************************************************* ' ' 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 da As OleDbDataAdapter Dim dSet As DataSet 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, ISBN, Publisher " & _ "FROM Book " & _ "ORDER BY Title" da = New OleDbDataAdapter(strSQL, dbConn) dSet = New DataSet da.Fill(dSet) 'set the source of the data for the datagrid control and bind it dgBooks.DataSource = dSet dgBooks.DataBind( ) Finally 'cleanup If (Not IsNothing(dbConn)) Then dbConn.Close( ) End If End Try End Sub 'bindData End Class 'CH01DatagridWithNextPrevNavVB1 End Namespace Example 1-19. DataGrid with next/previous navigation code-behind (.cs) //---------------------------------------------------------------------------- // // Module Name: CH01DatagridWithNextPrevNavCS1.aspx.cs // // Description: This class provides the code behind for // CH01DatagridWithNextPrevNavCS1.aspx // //**************************************************************************** using System; using System.Configuration; using System.Data; using System.Data.OleDb; using System.Web.UI.WebControls; namespace ASPNetCookbook.CSExamples { public class CH01DatagridWithNextPrevNavCS1 : 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) { // wire in the page index changed event this.dgBooks.PageIndexChanged += new DataGridPageChangedEventHandler(this.dgBooks_PageIndexChanged); if (!Page.IsPostBack) { bindData( ); } } // Page_Load //************************************************************************ // // ROUTINE: dgCustomers_PageIndexChanged // // DESCRIPTION: This routine provides the event handler for the page // index changed event of the datagrid. It is responsible // for setting the page index from the passed arguments // and rebinding the data. // //------------------------------------------------------------------------ private void dgBooks_PageIndexChanged(Object source, System.Web.UI.WebControls.DataGridPageChangedEventArgs e) { // set new page index and rebind the data dgBooks.CurrentPageIndex = e.NewPageIndex; bindData( ); } // dgCustomers_PageIndexChanged //************************************************************************ // // 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; OleDbDataAdapter da = null; DataSet dSet = 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, ISBN, Publisher " + "FROM Book " + "ORDER BY Title"; da = new OleDbDataAdapter(strSQL, dbConn); dSet = new DataSet( ); da.Fill(dSet, "Table"); // set the source of the data for the datagrid control and bind it dgBooks.DataSource = dSet; dgBooks.DataBind( ); } // try finally { //clean up if (dbConn != null) { dbConn.Close( ); } } // finally } // bindData } // CH01DatagridWithNextPrevNavCS1 } |