Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Custom Templated Pager Control

4.38/5 (5 votes)
27 Aug 2007CPOL6 min read 1   141  
A paging control particularly useful when implementing server-side paging.

Screenshot - screen1.gif

Introduction

Server-side paging of large resultsets is a common (and important) task for web developers. Combining it with the use of data controls, one needs to provide some form of paging UI. Simple forward and back buttons sometimes suffice, but where large numbers of pages are expected, they don't really provide a compelling interface. Setting up other forms of paging in this scenario can be time-consuming, whether you use the PagedDataSource class or create some custom method. And, I have frequently found that the design constraints of a particular site will require a laborious rewrite of my paging class.

There are a couple of other paging controls here on CodeProject to look at here and here. The paging control I've written differs (primarily) in that it's templated to allow for easy implementation of any flavor of paging UI. It responds to an ItemCommand event if you wish to use buttons of any sort, or works equally well (for the more SEO conscious) with querystring links.

The attached zip contains the compiled DLL, the full control source, and a couple of example implementations on a WebForm.

Background

This is the first templated control I've developed. I found there was a lot to be "discovered" in trying to do so. I won't go into all the details here, but the following resources proved to be useful:

There are lots of resources on server-side paging available, depending on what sort of database you use. It's pretty straightforward in Oracle and SQL Server 2005. This article provides a good look at methods available for SQL Server 2000.

Using the TemplatedPager

The easiest way to try out the control is to right click your VS2005 Toolbox, select Choose Items, browse to your unzip location for the attached file, and select TemplatedPager.dll. Then, drag an instance of the control from your toolbox onto your WebForm.

Templates

There are 8 templates available. All templates have access to the container page number property.

ASP.NET
<%#Container.PageNumber%> 

and the page count property.

ASP.NET
<%#Container.PageCount%> 

Note, in the separator template, these properties will not return anything as this template is not data-bound.

The HeaderTemplate will always return the current page via Container.PageNumber.

ASP.NET
<HeaderTemplate>
    Page <%#Container.PageNumber%> of <%#Container.PageCount%>:    
</HeaderTemplate>

FirstPageTemplate and the LastPageTemplate allow you to specify what any "go to first/last page" element should look and behave like. Container.PageNumber in this template is always 1 in the case of FirstPage, and the last page number in the case of LastPage. If this template is not included and the control's ShowFirst/ShowLast properties are set to true, this information will be rendered via the standard PageTemplate.

The PreviousPageTemplate and NextPageTemplate are pretty obvious. Unlike the first and last page templates, however, they are not rendered via the PageTemplate if their corresponding template does not exist in the control. Note, the ShowNext and ShowPrevious properties should be set to true for these templates to be rendered.

The CurrentPageTemplate allows the currently selected page to be styled differently than other pages, which will use the PageTemplate.

VB
<CurrentPageTemplate>
    <strong><%#Container.PageNumber%></strong>
</CurrentPageTemplate>
<PageTemplate>
    <asp:LinkButton ID="lP" CommandName="Page" 
      CommandArgument="<%#Container.PageNumber%>" 
          runat="server"><%#Container.PageNumber%></asp:LinkButton>
</PageTemplate>

Finally, the SeparatorTemplate allows you to specify HTML that should be rendered between each page number. Note, it is applied only between CurrentPageTemplate and the PageTemplate instances.

Properties

These can be set at design-time and/or run-time:

  • MaxPageNumbers How many page numbers to show.
  • PageCount You can either set this, or the PagedItemCount property. If you set this property, it will be used instead of PagedItemCount, regardless of what the value of PagedItemCount is.
  • PagedItemCount To have the page count calculated for you, set this property with the total number of items to be paged. Also, be sure to set the PageSize property to get an accurate page count. Calculation is CType(Math.Ceiling(PagedItemCount / PageSize), Integer).
  • PageNumber The current page number. Cannot be less than 1.
  • PageSize Number of items per page.
  • ShowFirst, ShowLast, ShowPrevious, ShowNext Booleans indicating whether to bind the associated templates.

Events

The ItemCommand event allows you to put button controls in your templates and respond to the events raised. For example:

VB
Protected Sub TemplatedPager1_ItemCommand(ByVal sender As Object, _
   ByVal e As Bxi.Web.UI.WebControls.PagerItemCommandEventArgs) _
   Handles TemplatedPager1.ItemCommand
        
    If e.CommandName = "Page" Then
        TemplatedPager1.PageNumber = e.CommandArgument
    End If
End Sub

Note: There is no need to call "DataBind" on this control. This is handled within the control by a requiresBind flag that gets set whenever control properties are altered.

Points of Interest

There are a number of "bumps in the road" when you're developing a (templated) control. Here are a few and the solutions I've discovered:

  1. I initially inherited from WebControl. It has a lot of unnecessary inherited properties for this control, so I altered to inherit from Control. Now, when I tried to add templates in the control, I was seeing the full list of server controls, rather than just my templates. This was resolved by adding the attributes ParseChildren(True) and PersistChildren(False). There's an informative blog about why this is necessary, heree.
  2. Inheriting from Control also resulted in no longer being able to access the container properties (e.g., Container.PageNumber). A lot of trial and error resulted in discovering that one needs to call the DataBind method on the template class (in my case, PagerItem) after adding it to the Controls collection, which interestingly is not necessary when inheriting from WebControl.
  3. It's silly, but I like to have a nice icon associated with a control, using the ToolboxBitmap attribute (to save you a few minutes, it's in System.Drawing). This actually took longer to accomplish than writing most of the control logic. Bob Powell has a good article here, which absolutely didn't work, but got me pointed in the right direction. If you follow all those instructions and can't get your icon to show, open your .dll in Reflector, look in the resources, and find your .bmp image (you should have set the build action on it to Embedded Resource). If it doesn't have a name that includes the root namespace (if there is one), the namespace, and any subdirectories it may reside in, in VS, rename the .bmp file to include all of these. In my case, I changed the file name to Bxi.Web.UI.WebControls.Resources.TemplatedPager.bmp and, bingo.
  4. Be aware of your root namespace. I prefer not to use one, and explicitly type the full namespaces out in the classes. It's easy to forget about it and then have issues with associating your control designer or your assembly TagPrefix, for example.

Improvements

I'd love to hear any feedback and suggested improvements, particularly if you have any advice/comments/suggestions on templated control development.

History

  • Version 1: August 28, 2007.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)