Creating a Repeater that Supports Pagination and Sorting
By Rachael Schoenbaum
Introduction
ASP.NET ships with a number of controls designed for displaying data, such as the DataGrid, DataList, and Repeater.
While the DataGrid is, by far, the most robust of the three data Web controls, the DataGrid's layout of its data is fairly
rigid. That is, with a DataGrid each record in the DataSource is going to be rendered as a single row in
a table, with each field as a table column. On the other end of the spectrum the Repeater control allows complete and total
control of the rendered output, but is lacking the advanced features inherent in the DataGrid, such as sorting and paging of
the underlying data. (For a more detailed discussion on the trade offs of each of the three data Web controls be sure
to read Scott Mitchell's article, Deciding
When to Use the DataGrid, DataList, or Repeater.)
After encountering a number of project requirements where I needed both the rendering flexibility of the Repeater and
the sorting and paging features of the DataGrid, I decided to create a custom, compiled Web control that would marry the flexibility
of the Repeater with the functionality of the DataGrid. In this article we'll examine this control of mine, SortablePaginationRepeater, and see how
to extend the Repeater to provide pagination and sorting. (Take a moment to view a
live demo of the control we'll be creating...)
Extending .NET Classes
Extending a class in .NET is basically like saying:
I really like the functionality of this class, but it's missing a few
things and/or doing a few things wrong for my needs. I don't want to attempt to re-write the functionality of the entire
class, I only want to change the pieces that don't work for me.
When you extend a class, you get access to all of its original public and protected members and are allowed to
override the ones you need to change. You can also add new functionality that the original never had in the first place.
This gives you a lot of freedom to use classes that come natively in .NET to provide the basic structure for the
functionality you want to create, without having to write it from scratch. There are a number of articles here on 4Guys that
illustrate how to extend an existing Web control:
Extending a class in .NET in code is really quite easy - just add the Inherits keyword to your class's definition, specifying
the class to extend. For example, to create a class named SortablePaginationRepeater that extends the Repeater class, you
would use the following syntax for the class's definition:
Public Class SortablePaginationRepeater : Inherits Repeater
Note: You can also put the Inherits keyword on the line following the class declaration (thereby removing the colon as well).
In order to enhance the Repeater to support paging and sorting we'll create a new class that uses the Repeater as the base
class. The new class, by default, will contain the complete functionality of the Repeater control; we'll add our own properties,
methods, and event handlers or override the Repeater's in order to add the necessary functionality for sorting and paging.
Step 1: Adding Properties to the Control
When extending an existing control, oftentimes you'll need to add some new properties that capture information important to
the extended control's new functionality. For example, our control is going to need a way for a page developer to pass in
information regarding how the data should be sorted, how many records to show per page, and so on.
When adding properties to a Web control it is important to use the ViewState collection so that any values
changed programmatically by the page developer persist across postbacks.
Here is an example of the property syntax utilizing ViewState as a backing store:
Public Property SortBy() As String
Get
If obj Is Nothing Then
Return vbNullString
Else
_Return Ctype(ViewState("SortBy"), String)
End If
End Get
Set(ByVal arg As String)
ViewState("SortBy") = arg
End Set
End Property
The following properties are available in the SortablePaginationRepeater control:
PageLocation – this defines where the pagination controls appear: at the top of the page, bottom of the page, or both.
PagerStyle – this allows the user to define the type of pagination controls that appear: Dropdown, NumericPages, NextPrev, or TextBox.
PageSize – the number of records that appear per page
PageButtonCount – used only for PagerStyle.NumericPages, this defines the number of page buttons that appear
CurrentPageIndex – the current page to display
SortBy – a string containing the column and direction to sort by
TableWidth – the width the table containing the pagination controls is; this can be expressed as a whole number or percentage
GoButtonCssClass – used only for PagerStyle.TextBox, this defines the CSS class for the button
SortColumn – stores the information that is used for the sorting control
Setting Up the Object for Pagination
.NET comes with a native object called the PagedDataSource, which provides a really convenient way to page through data.
The PagedDataSource class has a DataSource property that should be assigned the data to page through.
In addition, the PagedDataSource class contains properties to specify the number of records per page and the
current page you want to display. The PagedDataSource can then be bound to a data Web control and the appropriate
subset of records will be displayed. To provide paging in our control, then, instead of using the DataSource the
page developer passes in, we will internally use a PagedDataSource. Here's an example of how this is done:
Public Overrides Sub DataBind()
' Test for type of data source.
If TypeOf DataSource Is System.Collections.IEnumerable Then
_PagedDataSource.DataSource = DataSource
ElseIf TypeOf DataSource Is System.Data.DataView Then
Dim data As DataView = CType(DataSource, DataView)
_PagedDataSource.DataSource = data.Table.Rows()
ElseIf TypeOf DataSource Is System.Data.DataTable Then
Dim data As DataTable = CType(DataSource, DataTable)
_PagedDataSource.DataSource = data.DefaultView()
ElseIf TypeOf DataSource Is System.Data.DataSet Then
Dim data As DataSet = CType(DataSource, DataSet)
' Test if DataMember provided. If not, default to the 0th table in the set
If DataMember <> vbNullString AndAlso data.Tables.Contains(DataMember) Then
_PagedDataSource.DataSource = data.Tables(DataMember).DefaultView()
ElseIf data.Tables.Count > 0 Then
_PagedDataSource.DataSource = data.Tables(0).DefaultView()
Else
Throw New SortablePaginationException("DataSet doesn't have any tables.")
End If
Else
Throw New SortablePaginationException("DataSource must be of type " & _
"System.Collections.IEnumerable. The DataSource you provided is of type " & _
DataSource.GetType.FullName)
End If
'Set the page size as provided by the consumer
_PagedDataSource.PageSize = Me.PageSize
'Insure that the page doesn't exceed the maximum number of pages
'available
If Me.CurrentPageIndex >= _PagedDataSource.PageCount Then
Me.CurrentPageIndex = _PagedDataSource.PageCount - 1
End If
_PagedDataSource.CurrentPageIndex = Me.CurrentPageIndex
MyBase.DataSource = _PagedDataSource
MyBase.DataBind()
End Sub
You'll notice that not every data type can be converted into a PagedDataSource, hence the exception that is
thrown. Only enumerable objects (those capable of being counted or indexed) can be assigned as a DataSource for
the PagedDataSource. There are a couple of exceptions - namely DataViews, DataTables, and
DataSets - that may not be enumerable themselves but have properties that are. In this case, we set the
DataSource to the enumerable property of the object.
Another interesting thing to note is how DataSets get used. The Repeater has a native property called DataMember.
This property allows you to specify a particular DataTable of the DataSource to use. If the DataMember property
is not provided, the object uses the first table in the index of tables.
(For more information on the PagedDataSource, see Harrison Enholm's article,
Adding Paging Support to the Repeater or DataList with the PagedDataSource Class.)
Now that we've looked at how to implement paging, we're ready to turn our attention to the steps necessary to add sorting support.
In Part 2 we'll examine the steps taken to provide sorting support as well as see
the control used in an ASP.NET page.