The ASP.Net repeater control has over the last while become one of my favourite controls due to the fact it can be highly customised because it’s a templated control. Two shortcomings with the current implementation of the repeater control however are its lack of paging and sorting capabiltites. Of these I believe paging is perhaps the more desirable feature and thus I will now provide an outline of how to implement paging with a repeater using an SqlDataSource. I’ve chosen to work with an SqlDataSource as this I imagine is the most common underlying data source used with repeaters.
PagedDataSource class
The most popular way ASP.Net developers enable repeaters to page through large amounts of results is with the help of the PagedDataSource class. This is a class which
Encapsulates the paging-related properties of a data-bound control (such as DataGrid, GridView, DetailsView, and FormView) that allow it to perform paging and is used by control developers when providing paging support to a custom data-bound control.
Since this class can be used to provide paging support to custom data-bound controls it can of course be used by built in data-bound controls such Repeaters and DataLists to provide the same support. If you look on the MSDN page which I have linked to above you’ll notice however that the class implements the ICollection interface. This means that any underlying source you want to feed into the PagedDataSource class (which in turns feeds into the repeater itself) must also implement ICollection. The SqlDataSource class does not implement this interface and thus we must put the data into some class that does implement ICollection, in this case we are using a DataView. OK lets look the c# code behind.
-
public partial class _Default : System.Web.UI.Page
-
{
-
PlaceHolder innerPlaceHolder = new PlaceHolder();
-
protected void Page_Load(object sender, EventArgs e)
-
{
-
Session[“pageNumber”] = 1;
-
Page_with_Repeater();
-
int totalResults = (int)Session[“totalResults”];
-
-
//five represents the page size - could you session/viewstate
-
//to avoid hardcoding but for this sample it’s fine.
-
float numOflinks = ((float)totalResults / 5);
-
-
//determine how many links to create/display
-
if (numOflinks % 1 == 0) numOflinks = (int)numOflinks;
-
else if(numOflinks % 1 != 0) numOflinks = (int)numOflinks + 1;
-
-
for (int i = 1; i < numOflinks+1; i++)
-
{
-
LinkButton PagingLink = new LinkButton();
-
PagingLink.ID = “pagelink” + i.ToString();
-
PagingLink.Text = i.ToString();
-
PagingLink.Visible = true;
-
PagingLink.CommandArgument = i.ToString(); //used to detect result page required
-
PagingLink.Command += new CommandEventHandler(PagingLink_Command);
-
innerPlaceHolder.Controls.Add(PagingLink);
-
}
-
}
-
-
public void Page_with_Repeater()
-
{
-
//SqlDataSource does not implement ICollection and
-
//thus will not work with PageDataSource we therefore use
-
//a DataView instead which implements all required Interfaces
-
DataSourceSelectArguments arg = new DataSourceSelectArguments();
-
DataView dv = (DataView)SqlDataSource1.Select(arg);
-
-
//Instantiate an instance of PagedDataSource
-
//and sets its main properties
-
PagedDataSource PagedResults = new PagedDataSource();
-
PagedResults.DataSource = dv;
-
PagedResults.AllowPaging = true;
-
PagedResults.PageSize = 5; //CHANGE THIS ABOVE TOO
-
-
int pageIndex;
-
Int32.TryParse(Session[“pageNumber”].ToString(), out pageIndex);
-
PagedResults.CurrentPageIndex = pageIndex-1; //because this is indexed based
-
-
//after the PagedDataSource class is in place we can then
-
//feed this into the repeater itself
-
repeater1.DataSource = PagedResults;
-
repeater1.DataBind(); //repeater does not bind natively
-
-
//configure paging number - Google Style
-
//to do this we dynamically create X amount of links based on the total
-
//results and the PageSize - we can’t create these buttons here as
-
//events will only run if added in design time or page_init/page_load
-
Control OuterPanel = FindControlRecursive(repeater1, “placeLinks”);
-
OuterPanel.Controls.Add(innerPlaceHolder);
-
}
-
-
protected void SqlDataSource1_Selected(object sender, SqlDataSourceStatusEventArgs e)
-
{
-
//variable used to create X amount of buttons
-
Session[“totalResults”] = e.AffectedRows;
-
}
-
-
protected void PagingLink_Command(object sender, CommandEventArgs c)
-
{
-
Session[“pageNumber”] = c.CommandArgument.ToString();
-
Page_with_Repeater();
-
}
-
-
private Control FindControlRecursive(Control root, string id) { } //removed for clarity
-
-
}
All the important paging related code is encapsulated in the Page_with_Repeater() function, it’s all commented so I won’t repeat myself here. As far as what the code does, well it displays 5 rows of data at a time from the underlying datasource (in this case SqlDataSource1) in a repeater. LinkButtons are dynamically created and then added to the repeater to display page numbers as links to allow the user to select a specific result page. Often interfaces allow the user to select a specific page (as in this example) and to use previous and next buttons for working his or her way through data, on that note a good example of using buttons for repeater paging is given on the 4guysfromrolla.com website.
The corresponding .aspx markup for the c# code is very simple and contains a repeater (named ‘repeater1′) with an embedded panel (named ‘placeLinks’) and an SqlDataSource (named ‘SqlDataSource1′) which specifies an event hander for the ’selected’ event in order for us to create the correct amount of paging links.
Incidentally you may notice in the C# code above that I have used a custom function called FindControlRecursive to enable me to add the dynamically created placeholder (which contains all the page number linkbuttons) to the statically created panel within the repeater. This is a handy function I came across recently and which I often use in conjunction with repeater controls (and many other controls too). It accepts a root control and an id of the target control to look for. It works in a similar way to the standard FindControl method except it searches all controls (including child controls) in a control tree hierachy whereas FindControl will only search the specific control you pass it without examining any child controls.
That’s it - paging with a repeater using an SqlDataSource is implemented. As you can see it is not too difficult. If you have any questions please feel free to ask.


















