Introduction
When building ASP.NET Web applications, one of the most common tasks is displaying data. ASP.NET offers a bounty of data Web controls that make displaying data a breeze, but the most powerful data Web control - the DataGrid - imposes some limitations on the flexibility of laying out the data on the Web page. Recently I found myself needing a more flexible layout than the DataGrid's rigid column/row orientation, so I decided to go with the Repeater control so I could easily
customize
the HTML markup emitted.The Repeater control is great for situations like this, where you need a finer degree of control over the emitted HTML in order to layout the content in a unique or precise manner. One drawback to the Repeater is that it does not have built-in paging capability, a feature the DataGrid offers. Since I would need to display potentially hundreds of records in the catalog, it was essential that I provided paging support for the Repeater.
Fortunately there is a class in the .NET Framework that was designed to provide paged access to a data source. This class, the
PagedDataSource class, can be used by either the Repeater or DataGrid to mimic the paging capabilities of the DataGrid. Using the
PagedDataSourceclass you'll have to write a bit more code than you would when using the DataGrid, but the amount and complexity of the code you do have to write is fairly low. In this article we'll examine this class, and see a specific example of how to implement paging with a Repeater control.
Paging with the PagedDataSource Class
The
PagedDataSource class, found in the
System.Web.UI.WebControls namespace, encapsulates the properties needed to enable paging for a control. To implement paging in a control with the
PagedDataSource class, you'll need to perform the following steps:
- Get the data that you want to page through. This can be an array, a DataSet, a DataReader, or any other object that can be assigned to a data Web control's
DataSource property.
- Create the
PagedDataSource instance, and assign the data to page through to the PagedDataSource's DataSource property.
- Set the
PagedDataSource class's paging properties, such as setting AllowPaging to True, and setting PageSize (to indicate how many records per page to show).
- Assign the
PagedDataSource instance to the data Web control's DataSource property and call the data Web control's DataBind() method.
Example: Creating a Pageable Repeater
To examine how to use the
PagedDataSource class to provide pagination support in a Repeater, let's create a pageable Repeater. First we need to build the HTML content that includes the Repeater control; note that the HTML contains not only a Repeater, but also the paging navigation buttons and a Label indicating the page number. (Notice that the Repeater's
ItemTemplate is very simple in this example, and the same output could be possible with a DataGrid; but the concept holds - you could alter the Repeater's markup to allow for a much richer output that would not be possible with the DataGrid.)
<table width="100%" border="0"> <tr> <td> Repeater control with Paging functionality</td> </tr> <tr> <td> <asp:label id="lblCurrentPage" runat="server"></asp:label></td> </tr> <tr> <td> <asp:button id="cmdPrev" runat="server" text=" << "></asp:button> <asp:button id="cmdNext" runat="server" text=" >> "></asp:button></td> </tr> </table>
<table border="1"> <asp:repeater id="repeaterItems" runat="server"> <itemtemplate> <tr> <td> <b><%# DataBinder.Eval(Container.DataItem, "ItemName") %></b></td> <td> <b><%# DataBinder.Eval(Container.DataItem, "ItemDescription") %></b></td> <td> <b><%# DataBinder.Eval(Container.DataItem, "ItemPrice") %></b></td> <td> <b><%# DataBinder.Eval(Container.DataItem, "ItemInStock") %></b></td> </tr> </itemtemplate> </asp:repeater> </table> |
The HTML for a pageable Repeater can be as simple or as involved as you want. The code, though, is pretty straightforward. The first step is to write the code that will do all of the work of displaying the correct page of data in the Repeater. This is accomplished by first reading in the data to be paged through. For this example, I just created an XML file (
Items.xml) containing some sample data; this XML file is available in the code
download
at the end of this article.
// Read sample item info from XML document into a DataSet DataSet Items = new DataSet(); Items.ReadXml(MapPath("Items.xml")); |
Now that we have the data to page through, we need to create a
PagedDataSource instance and specify its
DataSource property and other germane properties.
// Populate the repeater control with the Items DataSet PagedDataSource objPds = new PagedDataSource(); objPds.DataSource = Items.Tables[0].DefaultView;
// Indicate that the data should be paged objPds.AllowPaging = true;
// Set the number of items you wish to display per page objPds.PageSize = 3; |
The
PagedDataSource also has a
CurrentPageIndex, which indicates what page of data to display. The following code shows assigning this property. Note that
CurrentPageIndex is assigned the value of a page-level property called
CurrentPage. We'll discuss this page-level property shortly.
// Set the PagedDataSource's current page objPds.CurrentPageIndex = CurrentPage - 1; |
Finally, we need to enable/disable the navigation buttons depending if we're on the first/last page, as well as update the Label Web control to indicate what page is currently being viewed. We can easily determine if we're on the first/last page using the
PagedDataSource's
IsFirstPage and
IsLastPage properties.
lblCurrentPage.Text = "Page: " + (CurrentPage + 1).ToString() + " of " + objPds.PageCount.ToString();
// Disable Prev or Next buttons if necessary cmdPrev.Enabled = !objPds.IsFirstPage; cmdNext.Enabled = !objPds.IsLastPage; |
Finally, we display the correct page of data by binding the
PagedDataSource object to the Repeater.
repeaterItems.DataSource = objPds; repeaterItems.DataBind(); |
Examining the CurrentPage Page-Level Property
Back in our earlier code example, we assigned the
PagedDataSource object's
CurrentPageIndex property to a page-level property called
CurrentPage. In order to remember the page of data to display across postbacks, it is important that the page index be maintained in the view state. This page-level property essentially wraps the complexity of reading from / writing to the view state, providing a convenient way to get and set the current page index. Here is the
CurrentPage property:
public int CurrentPage { get { // look for current page in ViewState object o = this.ViewState["_CurrentPage"]; if (o == null) return 0; // default page index of 0 else return (int) o; }
set { this.ViewState["_CurrentPage"] = value; } } |
Moving Between Pages of Data
To move from one page of data to another, the user visiting the Web page can click the next or previous buttons. These buttons, when clicked, cause a postback, and run server-side code that updates the
CurrentPage property and rebinds the data to the Repeater.
private void cmdPrev_Click(object sender, System.EventArgs e) { // Set viewstate variable to the previous page CurrentPage -= 1;
// Reload control ItemsGet(); }
private void cmdNext_Click(object sender, System.EventArgs e) { // Set viewstate variable to the next page CurrentPage += 1;
// Reload control ItemsGet(); } |
ItemsGet() is a page-level method (whose code we examined earlier) that contains the code to create the
PagedDataSource object and bind it to the Repeater.
Conclusion
As you can see, adding the paging functionality to the Repeater control is fairly simple thanks to the
PagedDataSource. You should now be able to create a paging Repeater control that will fit your needs; the lessons learned here can also be applied to adding pagination support to a DataList. Having the ability to page with a Repeater or DataList control will greatly enhance the usefulness of these data Web controls and, hopefully, you will find yourself using these versatile controls more often.Happy Programming!
By Harrison Enholm
Download the complete source code (in a ZIP file)
View a live demo!