Learn how to provide pagination support for the DataGrid Web control using the default paging mechanism. You will also discover the advantages of custom paging that allows the DataSource to contain only those records that will be displayed on the current page of data the user is viewing.

The examples we've looked at throughout the past seven chapters have displayed
small amounts of data, usually around 25 database records. These examples displayed
all of the data at one time. Although such an approach is sensible when dealing
with manageable amounts of data, imagine if we displayed 500 database records
all on one page. There would simply be too much data for the user to digest.

When presenting large amounts of data, many Web sites break the data up into
pages. For example, doing a search for "DataGrid" on Google.com returns
an estimated 114,000 results. Of course, I am not shown all 114,000 results
at once, just 10 at a time. At the bottom of the page is a list of page numbers,
allowing me to advance to the next page, or to one of the next 10 pages.

Google, obviously, is not the only Web site that breaks up large amounts of
data into readable pages. All search engines do this, whether the search engine
searches the entire World Wide Web or only a particular Web site. For example,
searching for products by a keyword on Amazon.com will display all matching
products 10 at a time.

In Chapter 7, "Sorting the DataGrid's Data," we looked at the
DataGrid's built-in properties to aid with sorting. These included the
AllowSorting property and the SortCommand event. As we'll
see in this chapter, the DataGrid also provides a number of properties and events
to assist with paging.

Adding Paging Support to the DataGrid

As we saw in Chapter 7, the first step to add sorting support to the DataGrid
is to set the AllowSorting property to True. Not surprisingly,
the DataGrid contains a similar property to enable paging: AllowPaging.
As with sorting, this property needs to be explicitly set to True to
enable the DataGrid's paging features.

Along with the AllowPaging property, there is a PageSize
property that specifies how many records to display per page. This property has
a default value of 10. By just setting the AllowPaging property to
True and (optionally) setting the PageSize property, the
DataGrid displays only the first PageSize number of rows from the
DataSource. Additionally, beneath the displayed rows is a row that has
< and > characters, which are rendered as hyperlinks.
The previous page can be reached by clicking the < link, and the
next page can be reached by clicking the > link. Figure 8.1 contains
a screenshot of a DataGrid with its AllowPaging property set to
True and its PageSize property set to 5 (see line 47
in Listing 8.1).

Note

As Figure 8.1 shows, when the page is
first loaded, the < character is simply a text character, not
a hyperlink. This is because when the page is first loaded, we are displaying
the first page of data. Therefore, there is no way the user can view the previous
page.

Figure
8.1. Setting AllowPaging to True displays only the PageSize
records per page.

Listing 8.1 contains the source code used for the ASP.NET Web page shown in
Figure 8.1. The code is similar to previous
examples we've looked at throughout this book.

Listing 8.1 The DataGrid's AllowPaging and PageSize
Properties Are Set

On line 47, you can see that the DataGrid's AllowPaging
property has been set to True, and its PageSize property has
been set to 5.

One important difference to note between many of our previous examples and
Listing 8.1 is that instead of populating our SQL query in a
SqlDataReader, we are using a DataSet (lines 29 through 35). The reason
we are using a DataSet is because when using the default paging, the
DataSource must be set to an object that implements the
ICollection interface. The DataSet implements this interface, but the
DataReader classes (SqlDataReader, OleDbDataReader, and so on)
do not. The default DataGrid paging requires that its DataSource
implement ICollection because the DataGrid needs to be able to
calculate the total number of records to determine how many total pages there
are for the given DataSource. Unfortunately, the only way to determine
how many total records are in a DataReader class is to iterate completely
through the DataReader's rows, incrementing some counter variable, after
which you cannot return to previous records.

Note

Although the DataGrid's default paging requires that the
DataSource implement the ICollection interface, the DataGrid
also offers custom paging. When using custom paging, the DataSource
need not implement ICollection. We will examine custom paging later in
this chapter.

Allowing the User to Page Through the Data

Unfortunately, getting the DataGrid to page the data is a bit more complicated
than simply setting the AllowPaging and PageSize properties.
In fact, the DataGrid displayed in Figure
8.1 doesn't perform any sort of paging. If you click the >
hyperlink to advance to the next page, nothing happens. That is, the ASP.NET
Web page is posted back, but the exact same data is displayed again.

The good news is that only a few lines of code are needed to provide full
paging support. Before we examine the code, though, let's take a brief
moment to discuss how the DataGrid knows what page of data is currently being
displayed, along with what happens when one of the < or
> hyperlinks is clicked.

Determining the Number of Pages and the Current Page

The DataGrid has two properties that can be used to determine what page of
data is currently being displayed and how many pages of data there are.

The CurrentPageIndex property is an integer value that indicates
what page is currently being displayed. This index is zero-based, meaning that
when the first page of data is being displayed, CurrentPageIndex equals
zero. More generally, when the nth page of data is being displayed,
CurrentPageIndex equals n  1.

The PageCount property indicates how many total pages there are; the
value of PageCount is equal to the number of records in the
DataSource divided by the number of records you are showing per page
(the value of the PageSize property). If there is any remainder left
over, the PageCount value is incremented to the nearest integer. That
is, if the DataSource has nine records and the PageSize
property is set to 5, PageCount will equal 2, because 9
divided by 5 is 1.8; because there is a remainder, the answer is incremented to
2. There would be two pages: The first would display records 1, 2, 3, 4, and 5,
and the second would display records 6, 7, 8, and 9.

Note

In mathematical terms, the PageCount is the ceiling of the number of
records in the DataSource divided by PageSize.

Because the CurrentPageIndex property specifies what page of data is
being displayed in the DataGrid, CurrentPageIndex should always be
between 0 and PageCount  1.

When one of the paging hyperlinks is clicked, the ASP.NET Web page performs a
postback. (Remember that your DataGrid must be placed within a Web form, as in
Listing 8.1, line 42.) When the page posts back, the DataGrid's
PageIndexChanged event is raised.

Our task will be to provide an event handler and wire it up to the
PageIndexChanged event. All that this event handler will have to do is
update the DataGrid's CurrentPageIndex property and rebind the
DataSource to the DataGrid.

Caution

It is vitally important that you remember to rebind the DataGrid in the
PageIndexChanged event handler. If you fail to do this, when attempting
to navigate to a different page, you will still be shown the first page of data.
This happens because when moving to a different page of data, the ASP.NET page
is posted back, the PageIndexChanged event fires, and the
PageIndexChanged event handler executes. If this event handler does not
rebind the DataGrid data, the DataGrid will be rendered using the ViewState,
which will redisplay the DataGrid's first page output. Therefore, as you
can in line 9 in Listing 8.2, the last line of the PageIndexChanged
event handler is a call to the BindData() subroutine.

The PageIndexChanged event handler must have the following
definition:

The DataGridPageChangedEventHandler class contains a
NewPageIndex property that specifies what page the user wants to view.
If the user clicks the < hyperlink, the value of the
DataGridPageChangedEventHandler's parameter NewPageIndex
property will be the value of the CurrentPageIndex property minus 1. If
the user clicks the > hyperlink, the value of the
DataGridPageChangedEventHandler's parameter NewPageIndex
property will be the value of the CurrentPageIndex property plus 1.

As mentioned previously, all we need to do in the event handler is update the
DataGrid's CurrentPageIndex property and rebind the
DataSource to the DataGrid. This simply involves setting the
DataGrid's CurrentPageIndex to the NewPageIndex property
of the DataGridPageChangedEventHandler parameter and then calling the
BindData() subroutine. The complete code for the
PageIndexChanged event handler can be seen here:

All that remains is to wire up the dgTitles_Paging event handler to
the DataGrid's PageIndexChanged event. This can be done through
the DataGrid's declaration. Listing 8.2 illustrates how to accomplish
this.

Listing 8.2 contains the dgTitles_Paging event handler we looked at
previously (lines 7 through 10). It also wires up the dgTitles_Paging
event handler to the DataGrid's PageIndexChanged event (line 19).
As with Listing 8.1, the AllowPaging and PageSize properties
are set to True and 5, respectively (line 18).

With this added event handler, the ASP.NET page in Listing 8.2 pages through
the data one page at a time as the user clicks the < and >
hyperlinks. You can refer back to Listing 8.1 to see a screenshot of the ASP.NET
Web page when you first visit it. Figure 8.2 contains a screenshot of the page
after the > hyperlink has been clicked once. Note that the records
displayed in Figure 8.2 are different
than those in Figure 8.1. Specifically,
they are records 610 from the titles database table.

Figure
8.2. When the user clicks the > hyperlink, the second page of
data is shown.