One of the compelling features of ASP.NET is its use of powerful controls like the DataGrid/GridView, DataList, FormView, etc. They are especially useful for presenting content in a paged manner. Unfortunately, the presentation is pretty limited to tabular data since the markup is encapsulated inside a mostly static table. What really would be nice is a control that paged, but gave finer control over the presentation of the data to the end user. The best candidate for this ability would be the Repeater, but it lacks any paging ability.
Well, that's what we're going to accomplish today. Not only are we going to give the repeater the ability to linearly page through data, but we're going to give it the ability to display numeric paging as well. For this tutorial, we're going to display back to the user a list of Flickr photo sets to browse.
One of the first things that we need to do is to model the data for storage in our database. Setup a database and create an Album table as follows:
Then, let's create an AlbumVO object to model the data. Just as a tip, make all the attributes private and create public accessors/mutators.
Now that we have that in place, create a new ASP.NET website and create a new page.
Let's start out with the markup and add a repeater to our page. Inside the
Now, let's go create the methods we need to bind our AlbumVOs to the repeater.
OK, now that we've got the bulk of the ground work laid, we need to create the linear paging mechanism, or put another way, paging one page at a time forwards or backwards. The first thing we need to do is create a PagedDataSource object. Under the hood, the DataGrid/GridView, FormView, DataList all use this PagedDataSource as the engine for paging data. Let's add one to the code behind and modify how the repeater binds its data. We'll set the data source of the PagedDataSource to our getAlbums() method and set the repeater's data source to the PagedDataSource. In a way, the PagedDataSource acts as a filter for the repeater.
Now that we've made that adjustment, we need to set some options on the PagedDataSource.
OK, now that the data source is setup, we need to add the ability to change pages and also store the current page index so that we don't loose it as part of the postback. Let's start with storing the current page index by encapsulating some ViewState logic.
Now, let's create some LinkButton controls in our markup to control changing pages.
Then, create the handlers that will tell our PagedDataSource to change pages and rebind the data to the repeater.
As you can see, I added some logic to hide/show the LinkButton objects based upon the index of the data source. It would be confusing to users to have a 'Next' button if there weren't anymore records to show, so let's hide them if there aren't anymore to see in a particular paging direction. This is also convenient if there is only one record in the whole data source, hiding both the Next' and 'Previous' buttons.
This is pretty nice looking paging control isn't it? We could also display the current page and total pages to a user which is nice, but what if we have many records to display and they have to click, one at a time, to traverse the whole paged source? That isn't very friendly, is it?
Here's where things get interesting. If you think about it, all the numeric paging scheme is, is a list of page indices, and page numbers, that are then pageable*. In short, we need a way to page those indices and numbers in a repeatable fashion. So, what we're going to do is create another PagedDataSource, and plug that into another repeater. If your head is spinning, hang on, well work this one step at a time.
First, let's create a data source that consists of a List of PageNumber objects.This is a very simple class that we can create:
In the following code snippet, all we're doing is creating a bunch of object based upon the number of objects in the first PagedDataSource we created.
After we've done that, we need to bind the List to the PagedDataSource and set the options for it. Then, we hook the PagedDataSource into the new repeater and set some options on the repeater.
Now that we we've taken care of the data in the code behind, let's go add some controls and flesh out what is actually going inside the repeater. For each item that will be displayed in this new repeater, let's put a LinkButton and specify the PageNumber as the text and the PageIndex as the command argument. Since we want this to be displayed in a tabular way, let's create a table to display the page numbers. The
and tags, respectively.
Now that we have that in place, we need to specify the command that should be executed and then add the handler in our code behind.
That's it! Test it out and you should have a fully functional numeric paging repeater. There are a few cleanup things that we should do to make the UI a little better, like making the current page unclickable when it is the current index. For that we should add a Label that displays the same data as the LinkButton, but only visible when the PageNumber is equal to the CurrentPageIndex+1. We also need to hide the LinkButton when its value meets the same condition.
Note that there are likely better algorithms out there and we could cache the page numbers data source, but for illustrative purposes, this accomplishes what we want to do.