Paging and Sorting Report Data
Paging and Sorting Report Data
Paging and Sorting Report Data
Tutorials
Paging and sorting are two very common features when displaying data in an online application. In this tutorial we'll take a first look at adding sorting and paging to our reports, which we will then build upon in future tutorials.
Introduction
Paging and sorting are two very common features when displaying data in an online application. For example, when searching for ASP.NET books at an online bookstore, there may be hundreds of such books, but the report listing the search results lists only ten matches per page. Moreover, the results can be sorted by title, price, page count, author name, and so on. While the past 23 tutorials have examined how to build a variety of reports, including interfaces that permit adding, editing, and deleting data, we ve not looked at how to sort data and the only paging examples we ve seen have been with the DetailsView and FormView controls. In this tutorial we ll see how to add sorting and paging to our reports, which can be accomplished by simply checking a few checkboxes. Unfortunately, this simplistic implementation has its drawbacks the sorting interface leaves a bit to be desired and the paging routines are not designed for efficiently paging through large result sets. Future tutorials will explore how to overcome the limitations of the out-of-thebox paging and sorting solutions.
Figure 1: Create a PagingAndSorting Folder and Add the Tutorial ASP.NET Pages Next, open the Default.aspx page and drag the SectionLevelTutorialListing.ascx User Control from theUserControls folder onto the Design surface. This User Control, which we created in the Master Pages and Site Navigation tutorial, enumerates the site map and displays those tutorials in the current section in a bulleted list.
Figure 2: Add the SectionLevelTutorialListing.ascx User Control to Default.aspx In order to have the bulleted list display the paging and sorting tutorials we ll be creating, we need to add them to the site map. Open the Web.sitemap file and add the following markup after the Editing, Inserting, and Deleting site map node markup: <siteMapNode title="Paging and Sorting" url="~/PagingAndSorting/Default.aspx" description="Samples of Reports that Provide Paging and Sorting Capabilities"> <siteMapNode url="~/PagingAndSorting/SimplePagingSorting.aspx" title="Simple Paging & Sorting Examples" description="Examines how to add simple paging and sorting support." /> <siteMapNode url="~/PagingAndSorting/EfficientPaging.aspx" title="Efficiently Paging Through Large Result Sets" description="Learn how to efficiently page through large result sets." /> <siteMapNode url="~/PagingAndSorting/SortParameter.aspx" title="Sorting Data at the BLL or DAL" description="Illustrates how to perform sorting logic in the Business Logic Layer or Data Access Layer." /> <siteMapNode url="~/PagingAndSorting/CustomSortingUI.aspx" title="Customizing the Sorting User Interface" description="Learn how to customize and improve the sorting user interface." /> </siteMapNode>
Figure 3: Update the Site Map to Include the New ASP.NET Pages
Figure 4: Retrieve Information About All of the Products Using the GetProducts() Method Since this report is a read-only report, there s no need to map the ObjectDataSource s Insert(), Update(), orDelete() methods to corresponding ProductsBLL methods; therefore, choose (None) from the drop-down list for the UPDATE, INSERT, and DELETE tabs.
Figure 5: Choose the (None) Option in the Drop-Down List in the UPDATE, INSERT, and DELETE Tabs Next, let s customize the GridView s fields so that only the products names, suppliers, categories, prices, and discontinued statuses are displayed. Furthermore, feel free to make any field-level formatting changes, such as adjusting the HeaderText properties or formatting the price as a currency. After these changes, your GridView s declarative markup should look similar to the following: <asp:GridView ID="Products" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" EnableViewState="False"> <Columns> <asp:BoundField DataField="ProductName" HeaderText="Product" SortExpression="ProductName" /> <asp:BoundField DataField="CategoryName" HeaderText="Category" ReadOnly="True" SortExpression="CategoryName" /> <asp:BoundField DataField="SupplierName" HeaderText="Supplier" ReadOnly="True" SortExpression="SupplierName" /> <asp:BoundField DataField="UnitPrice" HeaderText="Price" SortExpression="UnitPrice" DataFormatString="{0:C}" HtmlEncode="False" /> <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" SortExpression="Discontinued" /> </Columns> </asp:GridView> Figure 6 shows our progress thus far when viewed through a browser. Note that the page lists all of the products in one screen, showing each product s name, category, supplier, price, and discontinued status.
Figure 6: Each of the Products are Listed (Click to view full-size image)
Figure 7: Check the Enable Paging Checkbox to Add Paging Support (Click to view full-size image) Enabling paging limits the number of records shown per page and adds a paging interface to the GridView. The default paging interface, shown in Figure 7, is a series of page numbers, allowing the user to quickly navigate from one page of data to another. This paging interface should look familiar, as we ve seen it when adding paging support to the DetailsView and FormView controls in past tutorials. Both the DetailsView and FormView controls only show a single record per page. The GridView, however, consults its PageSize property to determine how many records to show per page (this property defaults to a value of 10). This GridView, DetailsView, and FormView s paging interface can be customized using the following properties: PagerStyle indicates the style information for the paging interface; can specify settings like BackColor,ForeColor, CssClass, HorizontalAlign, and so on. PagerSettings contains a bevy of properties that can customize the functionality of the paging interface;PageButtonCount indicates the maximum number of numeric page numbers displayed in the paging interface (the default is 10); the Mode property indicates how the paging interface operates and can be set to: NextPrevious shows a Next and Previous buttons, allowing the user to step forwards or backwards one page at a time NextPreviousFirstLast in addition to Next and Previous buttons, First and Last buttons are also included, allowing the user to quickly move to the first or last page of data Numeric shows a series of page numbers, allowing the user to immediately jump to any page
NumericFirstLast in addition to the page numbers, includes First and Last buttons, allowing the user to quickly move to the first or last page of data; the First/Last buttons are only shown if all of the numeric page numbers cannot fit Moreover, the GridView, DetailsView, and FormView all offer the PageIndex and PageCount properties, which indicate the current page being viewed and the total number of pages of data, respectively. The PageIndexproperty is indexed starting at 0, meaning that when viewing the first page of data PageIndex will equal 0.PageCount, on the other hand, starts counting at 1, meaning that PageIndex is limited to the values between 0 andPageCount - 1. Let s take a moment to improve the default appearance of our GridView s paging interface. Specifically, let s have the paging interface right-aligned with a light gray background. Rather than setting these properties directly through the GridView s PagerStyle property, let s create a CSS class in Styles.css named PagerRowStyle and then assign the PagerStyle s CssClass property through our Theme. Start by opening Styles.css and adding the following CSS class definition: .PagerRowStyle { background-color: #ddd; text-align: right; } Next, open the GridView.skin file in the DataWebControls folder within the App_Themes folder. As we discussed in the Master Pages and Site Navigation tutorial, Skin files can be used to specify the default property values for a Web control. Therefore, augment the existing settings to include setting the PagerStyle s CssClass property toPagerRowStyle. Also, let s configure the paging interface to show at most five numeric page buttons using theNumericFirstLast paging interface. <asp:GridView runat="server" CssClass="DataWebControlStyle"> <AlternatingRowStyle CssClass="AlternatingRowStyle" /> <RowStyle CssClass="RowStyle" /> <HeaderStyle CssClass="HeaderStyle" /> <FooterStyle CssClass="FooterStyle" /> <SelectedRowStyle CssClass="SelectedRowStyle" /> <PagerStyle CssClass="PagerRowStyle" /> <PagerSettings Mode="NumericFirstLast" PageButtonCount="5" /> </asp:GridView>
Figure 8 shows the web page when visited through a browser after the GridView s Enable Paging checkbox has been checked and the PagerStyle and PagerSettings configurations have been made through theGridView.skin file. Note how only ten records are shown, and the paging interface indicates that we are viewing the first page of data.
Figure 8: With Paging Enabled, Only a Subset of the Records are Displayed at a Time (Click to view fullsize image) When the user clicks on one of the page numbers in the paging interface, a postback ensues and the page reloads showing that requested page s records. Figure 9 shows the results after opting to view the final page of data. Notice that the final page only has one record; this is because there are 81 records in total, resulting in eight pages of 10 records per page plus one page with a lone record.
Figure 9: Clicking On a Page Number Causes a Postback and Shows the Appropriate Subset of Records (Click to view full-size image)
This event handler assigns the PagingInformation Label s Text property to a message informing the user the page they are currently visiting Products.PageIndex + 1 out of how many total pages Products.PageCount (we add 1 to the Products.PageIndex property because PageIndex is indexed starting at 0). I chose the assign this Label s Text property in the DataBound event handler as opposed to the PageIndexChanged event handler because the DataBound event fires every time data is bound to the GridView whereas the PageIndexChanged event handler only fires when the page index is changed. When the GridView is initially data bound on the first page visit, the PageIndexChanging event doesn t fire (whereas the DataBound event does). With this addition, the user is now shown a message indicating what page they are visiting and how many total pages of data there are.
Figure 10: The Current Page Number and Total Number of Pages are Displayed (Click to view full-size image) In addition to the Label control, let s also add a DropDownList control that lists the page numbers in the GridView with the currently viewed page selected. The idea here is that the user can quickly jump from the current page to another by simply selecting the new page index from the DropDownList. Start by adding a DropDownList to the Designer, setting its ID property to PageList and checking the Enable AutoPostBack option from its smart tag. Next, return to the DataBound event handler and add the following code: // Clear out all of the items in the DropDownList PageList.Items.Clear(); // Add a ListItem for each page for (int i = 0; i < Products.PageCount; i++) { // Add the new ListItem ListItem pageListItem = new ListItem(string.Concat("Page ", i + 1),
i.ToString()); PageList.Items.Add(pageListItem); // select the current item, if needed if (i == Products.PageIndex) pageListItem.Selected = true; } This code begins by clearing out the items in the PageList DropDownList. This may seem superfluous, since one wouldn t expect the number of pages to change, but other users may be using the system simultaneously, adding or removing records from the Products table. Such insertions or deletions could alter the number of pages of data. Next, we need to create the page numbers again and have the one that maps to the current GridView PageIndexselected by default. We accomplish this with a loop from 0 to PageCount - 1, adding a new ListItem in each iteration and setting its Selected property to true if the current iteration index equals the GridView s PageIndexproperty. Finally, we need to create an event handler for the DropDownList s SelectedIndexChanged event, which fires each time the user pick a different item from the list. To create this event handler, simply double-click the DropDownList in the Designer, then add the following code: protected void PageList_SelectedIndexChanged(object sender, EventArgs e) { // Jump to the specified page Products.PageIndex = Convert.ToInt32(PageList.SelectedValue); } As Figure 11 shows, merely changing the GridView s PageIndex property causes the data to be rebound to the GridView. In the GridView s DataBound event handler, the appropriate DropDownList ListItem is selected.
Figure 11: The User is Automatically Taken to the Sixth Page When Selecting the Page 6 Drop-Down List Item (Click to view full-size image)
Figure 12: The Results Have Been Sorted by the UnitPrice in Ascending Order (Click to view full-size image)
When binding an ObjectDataSource to the GridView through the drop-down list in the GridView s smart tag, each GridView field automatically has its SortExpression property assigned to the name of the data field in theProductsRow class. For example, the ProductName BoundField s SortExpression is set to ProductName, as shown in the following declarative markup: <asp:BoundField DataField="ProductName" HeaderText="Product" SortExpression="ProductName" /> A field can be configured so that it s not sortable by clearing out its SortExpression property (assigning it to an empty string). To illustrate this, imagine that we didn t want to let our customers sort our products by price. TheUnitPrice BoundField s SortExpression property can be removed either from the declarative markup or through the Fields dialog box (which is accessible by clicking on the Edit Columns link in the GridView s smart tag).
Figure 13: The Results Have Been Sorted by the UnitPrice in Ascending Order Once the SortExpression property has been removed for the UnitPrice BoundField, the header is rendered as text rather than as a link, thereby preventing users from sorting the data by price.
Figure 14: By Removing the SortExpression Property, Users Can No Longer Sort the Products By Price (Click to view full-size image)
Figure 15: Clicking the Button Orders the Products From the Most Expensive to the Least (Click to view full-size image)