Using ASP.NET 3.5's ListView and DataPager Controls: The Ultimate DataPager Interface
By Scott Mitchell
A Multipart Series on ASP.NET's ListView and DataPager Controls |
---|
This article is one in a series of articles on ASP.NET's ListView and DataPager controls, which were introduced with ASP.NET version 3.5.
|
Introduction
The previous installment in this ongoing article series showed how to configure the DataPager control to generate an SEO-friendly paging interface. By default, the DataPager renders its paging interface as a series of Buttons, LinkButtons, or ImageButtons that, when clicked, trigger a postback. The problem with postbacks is that they are not crawled by search engine spiders, meaning that with the default behavior only the first page of data will make it into the search engines' indexes. Fortunately, the DataPager's paging interface can be configured to include the page number in the querystring. When configured this way, the DataPager renders its paging interface using hyperlinks with URLs like
Products.aspx?Page=PageNumber
. With this approach a search engine will happily
crawl through each page of data.
Shortly after publishing Creating an SEO-Friendly Paging Interface, a number of readers asked if it would
be possible to create a paging interface that moved the page number from the querystring into the URL. Rather than having a paging interface that linked to pages
with URLs like Products.aspx?Page=PageNumber
, these readers wanted to have URLs like: Products/PageNumber
. Such terse, descriptive URLs
are possible with ASP.NET Routing, a feature added to the .NET Framework 3.5 SP1. While typically used
in ASP.NET MVC applications, ASP.NET Routing can also be used in Web
Form applications.
This article shows how to use ASP.NET Routing with the ListView and DataPager controls to create the ultimate paging interface. Read on to learn more!
Please be sure to read Creating an SEO-Friendly Paging Interface before continuing on with this article...
Using ASP.NET Routing in the Paging Interface
One of the highlights of ASP.NET MVC is its ability to use ASP.NET Routing to create terse, "hackable", SEO-friendly URLs. While ASP.NET Routing is used by default in ASP.NET MVC applications, it can also be used in WebForm applications. Using ASP.NET Routing Without ASP.NET MVC gives detailed step-by-step instructions on what you need to do to start using ASP.NET Routing in a WebForms application.
In a nutshell, using ASP.NET Routing entails defining routing rules, which indicate what route patterns map to what ASP.NET pages. Consider the demo we looked at in
Creating an SEO-Friendly Paging Interface. In this demo we had a single ASP.NET page named QueryStringPaging.aspx
that used a ListView and DataPager to display
data from the Northwind database's Products
table. A querystring field named Page
was used to indicate the page of data to display. For example, to view
the first page of data we'd visit QueryStringPaging.aspx
, or QueryStringPaging.aspx?Page=1
; to view the second page we'd visit
QueryStringPaging.aspx?Page=2
; and so on.
Using ASP.NET Routing we can create a routing rule that defines a pattern of the form /Products/PageNumber
that maps to the ASP.NET page
QueryStringPaging.aspx?Page=PageNumber
. With this routing rule in effect, a user can view the first page of products by visiting
/Products
, or /Products/1
. To view the second page of data they'd visit /Products/2
, and so on. Such a routing rule gives us an ideal
URL for our product listing:
- The URL is very readable.
- The URL is "hackable." A user who is viewing the fourth page of data -
/Products/4
- can infer that by removing the "/4" from the URL he will return to the first page of data. - The URLs are SEO-friendly
- Configure the website to use ASP.NET Routing and implement the routing rules, and
- Customize the markup generated by the DataPager so that the paging interface renders hyperlinks that use the appropriate URLs -
/Products/PageNumber
rather thanQueryStringPaging.aspx?Page=PageNumber
Implementing ASP.NET Routing - Preamble
To use ASP.NET Routing in a WebForms application you need to perform five steps:
- Add a reference to
System.Web.Routing
to your project. - Add the
UrlRoutingModule
HTTP Module andUrlRoutingHandler
HTTP Handler inWeb.config
. - Define the routes in
Global.asax
. - Create the route handler class(es).
- Create the ASP.NET page(s) that process the requests.
Implementing ASP.NET Routing - Step 3: Defining The Routes In Global.asax
The
Global.asax
file can include event handlers for application-wide events. Whenever the application starts we need to define the routing rules. Therefore, these
go in the Global.asax
file's Application_Start
event handler. For this demo we need a single routing rule of the form
Products/Page
. The following code implements this functionality:
Sub Application_Start(sender As Object, e As EventArgs)
|
The Application_Start
event handler fires whenever the application starts. It calls the RegisterRoutes
method, passing in the site-wide collection
of routing rules (RouteTable.Routes
). The RegisterRoutes
method then adds a new route. It starts by defining the default values for the route using
a RouteValueDictionary
. Specifically, a default value of 1 is defined for the Page parameter, which means if someone visits /Products
- that is,
there is no trailing page number - then a default page value of 1 will be used. The final line of code in the RegisterRoutes
method adds a new route rule to
the site-wide routes. The route is named ProductRoute
and the routing is handled by the ProductRouteHandler
.
Implementing ASP.NET Routing - Step 4: Creating the Route Handler Class
When ASP.NET detects an incoming request of the form
/Products
or /Products/somePageNumber
it invokes the specified route handler class
(ProductRouteHandler
). This route handler class is pretty straightforward. In short, it sends the user onto the ASP.NET page that contains the ListView and
DataPager, which I've named FancyPaging.aspx
. It also needs to pass along the page number value in the route (such as 1, 2, etc.). This is passed from the
ProductRouteHandler
route handler class to the FancyPaging.aspx
page via the HttpContext.Items
collecting.
Imports System.Web.Compilation
|
Implementing ASP.NET Routing - Step 5: Creating the ASP.NET Page That Processes The Requests
The
FancyPaging.aspx
page uses ListView and DataPager controls to display the products from the Northwind database. A user may visit this page directly, by entering
FancyPaging.aspx
in their browser's Address bar, or they may reach it indirectly via the routing rule defined in step 3. FancyPaging.aspx
is similar to
the QueryStringPaging.aspx
page examined in Creating an SEO-Friendly Paging Interface, with two
notable exceptions:
- In
QueryStringPaging.aspx
the DataPager would automatically inspect the querystring to determine which page to show. Since we've circumvented this process we need to write code forFancyPaging.aspx
that displays the appropriate page of data based on the page specified through the route. Recall that this information is passed toFancyPaging.aspx
viaHttpContext.Current.Items("PageNumber")
. - The DataPager in
QueryStringPaging.aspx
rendered its own paging interface with very little work on our end. We used NextPreviousPagerField and NumericPagerField controls in the DataPager's<Fields>
section to generate the paging interface. ForFancyPaging.aspx
we need to create the paging interface manually so that we can have the hyperlinks in the paging interface reference our custom URL structure (/Products/pageNumber
rather than the format the DataPager uses (FancyPaging.aspx?Page=pageNumber
).
When the FancyPaging.aspx
page is first visited we need to determine which page of data to display. The following code in the Page_Load
event handler
starts by reading in the requested page number from the HttpContext.Items
collection. Next, it computes the starting row index based on the page number and
how many rows to show per page. Finally, it calls the DataPager's SetPageProperties
method, passing in the starting row index, the maximum number of rows, and a
value of True that instructs the DataPager to have the ListView rebind its data to get the correct page of data.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
|
Here, ProductListPager
is the ID
of the DataPager control on the page. ProductListPager.PageSize
specifies how many records to show
per page of data. The starting row index is computed by taking the requested page number, subtracting one, and then multiplying it by the number of records to show per page.
The starting row index and number of records to show per page are then passed into the DataPager's SetPageProperties
method, which instructs the DataPager to
go retrieve the appropriate page of data.
Generating the DataPager's Paging Interface
At this point the
FancyPaging.aspx
page can be visited via the route /Products/pageNumber
, which loads the appropriate page of products.
However, the DataPager renders its paging interface with hyperlinks that send the user to FancyPaging.aspx?Page=pageNumber
. We need to update the DataPager's
paging interface so that the hyperlinks send the user to /Products/pageNumber
.
Unfortunately, the DataPager does not have a property you can set to customize the paging interface URL. Instead, we must use a TemplatePagerField and then craft the paging
interface's markup by hand. (For more information on using the DataPager's TemplatePagerField see Paging Through
Data with the ListView and DataPager Controls.) We are going to programmatically construct the markup for the paging interface, so our DataPager just needs an empty
<PagerTemplate>
within the TemplatePagerField:
<asp:DataPager ID="ProductListPager" runat="server"
|
Then, in the ListView's PreRender
event, we can build up this paging interface (see the code below). The code starts by determining the current page being viewed
and the total number of pages. It then adds hyperlinks to the DataPager's template for the previous page, the next page, and numeric pages. Each paging interface hyperlink is
added to the template via a call to the CreateLink
method, which adds a Label Web control for disabled pager buttons, and a HyperLink Web control for enabled
ones. The NavigateUrl
property of the HyperLink is assigned to the value returned by the Helpers.FormatProductUrl(pageNumber)
method, which
uses the RouteTable.Routes
collection's GetVirtualPath
method to determine the appropriate routing URL for the specified page number.
Protected Sub ProductList_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles ProductList.PreRender
|
The following two screen shots show the paging interface in action. The first screen shot shows the paging interface when first visited (/Products
). Note how the Previous
link is grayed out. Also note how the paging interface shows the last two page links, regardless of what page you're on. This lets the user quickly know how many total
pages of data there are.

The second one shows the paging interface when visiting 11th page of data (/Products/11
). Note how the first two paging links are always visible. This
enables users to quickly jump back to the beginning of the product list.

Happy Programming!
Further Readings:
Attachments