Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Paging Data with ASP.NET URL Routing

0.00/5 (No votes)
10 Dec 2009 1  
A really cool feature in ASP.NET 4.0 is URL routing for web forms. It, however, does not work well with the DataPager control. An alternative data paging interface comes to the rescue, solving other paging problems as well.

Introduction

ASP.NET 3.5 contains a very useful component - the DataPager control. This control allows you to page contents of any control implementing the IPageableItemContainer interface - which is so far only the universal ListView control, also part of ASP.NET 3.5.

ASP.NET 4.0 adds another cool feature to web forms: URL routing, first seen in ASP.NET MVC. The routing engine allows you to create canonical and user-friendly URLs easier than hacking URL rewriting. You can read more about URL routing in this blog post by Scott Guthrie.

The problem is that these two features do not work well together, and the DataPager control does have several other limitations.

  • In the current ASP.NET 4.0 beta 2, the DataPager does not work at all when the QueryStringField property is specified. This is a known bug and will be fixed in the final release (bug #515348). But for early adopters, this is currently a problem.
  • The DataPager control supports only query string or JavaScript postback for paging. You can't have the current page index specified in the route.
  • DataPager renders its own UI, which can be customized, but not easily, especially with regard to CSS styling.

Solution

My solution is to write my own data paging control. This control uses the same IPageableItemContainer infrastructure like DataPager does, but with a different UI generation philosophy.

Instead of rendering its own interface, the control uses the standard HyperLink controls, sets their NavigateUrl property, and based on the configuration, can hide or disable them if they are not needed.

This control works as a control extender, extending any IPageableItemContainer (in short: ListView) control.

Configuration properties of the DataPagerExtender control

  • TargetControlID - ID of the control that should be paged.
  • PageSize - number of items on a single page; defaults to 10.
  • PageIndexSource - where to get the current page index from. Can be either RouteParameter (default) or QueryString.
  • CollectionKey - sets the name of the query string field or route parameter (see above) to get the current page index from.
  • InactiveLinkMode - specifies how to behave when a link is to be inactive (i.e., "previous" link on first page). The default value is Ignore, in which case the link is simply ignored and left unchanged. When set to Hide, the particular link control is hidden (Visible=false), and when set to Disable, the control is disabled (Enabled=false).
  • FirstLinkID, PreviousLinkID, NextLinkID, LastLinkID - these properties specify the IDs of HyperLink controls used for navigation. If you leave a property blank, it is ignored. Thus, if you want only the "previous" and "next" links, only specify PreviousLinkID and NextLinkID.

Using the DataPagerExtender control

First of all, display your data in a ListView control the usual way. Then, create four HyperLink controls for navigating to the first, previous, next, and last page (marked in bold in the code below):

<asp:ListView ID="ListView1" runat="server" DataSourceID="LinqDataSource1">
  <LayoutTemplate>
    <table>
      <thead>
        <tr>
          <th>ProductID</th>
          <th>ProductName</th>
          <th>UnitPrice</th>
        </tr>
      </thead>
      <tbody>
        <asp:PlaceHolder ID="itemPlaceholder" runat="server" />
      </tbody>
      <tfoot>
        <tr>
          <td colspan="3">
            <div style="float: left">
              <asp:HyperLink ID="LinkFirst" runat="server" Text="<< first" />
              <asp:HyperLink ID="LinkPrevious" runat="server" Text="< previous" />
            </div>
            <div style="float: right">
              <asp:HyperLink ID="LinkNext" runat="server" Text="next >" />
              <asp:HyperLink ID="LinkLast" runat="server" Text="last >>" />
            </div>
          </td>
        </tr>
      </tfoot>
  </LayoutTemplate>
  <ItemTemplate>
    <tr>
      <td>
        <asp:Label runat="server" Text='<%# Eval("ProductID") %>' />
      </td>
      <td>
        <asp:Label runat="server" Text='<%# Eval("ProductName") %>' />
      </td>
      <td>
        <asp:Label runat="server" Text='<%# Eval("UnitPrice") %>' />
      </td>
    </tr>
  </ItemTemplate>
</asp:ListView>
<asp:LinqDataSource ID="LinqDataSource1" runat="server" TableName="Products"
                    ContextTypeName="NorthwindDataContext" OrderBy="ProductName" 
                    Select="new (ProductID, ProductName, UnitPrice)" />

Then, add the DataPagerExtender control (in my case, I registered it on the my prefix, and I'm using the query string):

<my:DataPagerExtender ID="DPE1" runat="server" TargetControlID="ListView1" 
                      PageIndexSource="QueryString" CollectionKey="Page" 
                      FirstLinkID="LinkFirst" LastLinkID="LinkLast" 
                      NextLinkID="LinkNext" PreviousLinkID="LinkPrevious" />

Using the DataPagerExtender with routing

First of all, you must slightly modify the control reference above:

<my:DataPagerExtender ID="DPE1" runat="server" TargetControlID="ListView1" 
                      PageIndexSource="RouteParameter" CollectionKey="Page" 
                      FirstLinkID="LinkFirst" LastLinkID="LinkLast" 
                      NextLinkID="LinkNext" PreviousLinkID="LinkPrevious" />

Then, you must create some route, which contains the {Page} route parameter (and possibly some others). It's recommended that this parameter would default to "1", so the first page is shown when none is explicitly specified:

void Application_Start(object sender, EventArgs e) {
    RouteTable.Routes.MapPageRoute("PagedProducts",     // route name
        "pagedproducts/{Page}",                         // path
        "~/Products2.aspx",                             // internal handler
        false,                                          // do not check physical file
        new RouteValueDictionary { { "Page", "1" } });  // default to first page
}

Limitations

Compared to the original DataPager control, my DataPagerExtender has several limitations:

  • It does not support postback for paging.
  • Only the Next/Previous etc., pager style is supported, not a list of page numbers with direct jump capability.
  • There is no declarative way to display paging information (e.g., "showing items 1-10 from 100, page 1 of 10").

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here