Introduction


When building ASP.NET Web applications, one of the most common tasks is displaying data. ASP.NET offers a variety of data Web controls that make displaying data a breeze, but the most powerful data Web control - the Gridview - imposes some limitations on the flexibility of laying out the data on the Web page.

The Datalist 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 Datalist is that it does not have built-in paging capability, a feature the Gridview offers. Since we need to display potentially hundreds of records in the catalog, it is essential to provide paging support for the Datalist.

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 Datalist or Repeater to mimic the paging capabilities of the GridView. Using the PagedDataSource class you'll have to write a bit more code than you would when using the Gridview, but the amount and complexity of the code you do have to write is fairly low.

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:

1.  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.

2.  Create the PagedDataSource instance, and assign the data to page through to the PagedDataSource's DataSource property.

3.  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).

4.  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 Datalist


To examine how to use the PagedDataSource class to provide pagination support in a Datalist, let's create a pageable Datalist. First we need to update the product web user control that includes the Datalist control; note that the HTML contains not only a Datalist, but also the paging navigation buttons and a Label indicating the page number; we included all of these controls in a panel.

asp:Panel ID="pnlNavigation" runat="server" Visible="false">
&nbsp;&nbsp;asp:Button ID="btnPrev" runat="server" Text=" < " OnClick="btnPrev_Click"
Height="18px"</asp:Button&nbsp;&nbsp;
asp:Label ID="lblCurrentPage" runat="server"</asp:Label&nbsp;&nbsp; &nbsp;asp:Button
ID="btnNext" runat="server" Text=" > " OnClick="btnNext_Click" Height="18px">
</asp:Button
</asp:Panel
asp:DataList ID="DataList1" runat="server"
RepeatColumns="2" Width="100%" onitemdatabound="DataList1_ItemDataBound"
ItemTemplate
table class="style1">
tr
td colspan="2"
asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl='<%# "~/Product.aspx?PID=" + Eval("ProductID").ToString() %>' Text='<%# Eval("name") %>'</asp:HyperLink
</td
</tr
tr
td
asp:Image ID="Image1" runat="server" Height="81px"
ImageUrl='<%# "~\\ProductImages\\" + Eval("Thumbnail") %>' Width="65px" />
</td
td
asp:Label ID="Label2" runat="server" Text='<%# Eval("Description") %>'</asp:Label
br/>
br/>
Price :asp:Label ID="Label3" runat="server"
Text='<%# Eval("Price", "{0:C}") %>'</asp:Label
</td
</tr
</table
asp:PlaceHolder ID="APH" runat="server"</asp:PlaceHolder
br
br</br
</br
</ItemTemplate
</asp:DataList

The HTML for a pageable Datalist 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 Datalist. This is accomplished by several methods, in our example we created an sql datasource that retrieved the data from the stored procedure.

asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:BalloonShopConnection %>"
SelectCommand="CatalogGetProductInCategory"
SelectCommandType="StoredProcedure">
SelectParameters
asp:QueryStringParameter Name="CategoryID"
QueryStringField="CategoryID" Type="Int32" />
</SelectParameters
</asp:SqlDataSource

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 Datalist control from the sqldatasource
DataSourceSelectArguments arg = new DataSourceSelectArguments();
PagedDataSource objPds = new PagedDataSource();
objPds.DataSource = SqlDataSource1.Select(arg);
objPds.AllowPaging = true;
objPds.PageSize = 10;

The PagedDataSource also has a CurrentPageIndex, which indicates what page of data to display. The following code shows how to assign 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 ;

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();
//Enable/Disable Prev and Next buttons
btnPrev.Enabled = !objPds.IsFirstPage;
btnNext.Enabled = !objPds.IsLastPage;

Finally, we display the correct page of data by binding the PagedDataSource object to the Datalist. We add one more line to check if there is only one page then we should not show the panel (the visible property is set to false).

DataList1.DataSource = objPds;
DataList1.DataBind();
if (objPds.PageCount > 1)
{
pnlNavigation.Visible = true;
}

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 Datalist.

public void btnNext_Click(object sender, System.EventArgs e)
{
// Set viewstate variable to the next page
CurrentPage += 1;
// Reload control
BindPagedDataSource();
}
public void btnPrev_Click(object sender, System.EventArgs e)
{
// Set viewstate variable to the previous page
if (CurrentPage > 0)
CurrentPage -= 1;
// else
//CurrentPage = 1;
// Reload control
BindPagedDataSource();
}

BindPagedDataSource()is a page-level method (whose code we examined earlier) that contains the code to create the PagedDataSource object and bind it to the Datalist.

Updating the page load event

We have to make sure to set the currentpage = 0 the first time the page is loaded. In our example we are using the same page for the categories and the products this is why we need to check not to call the BindPagedDataSource() method unless a category had been chosen.

protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
CurrentPage = 0;
if (HttpContext.Current.Request.QueryString["CategoryID"] != null)
BindPagedDataSource();
}
}

Further work

-  We can add two buttons that will assign the first and last page; don’t forget to disable them when appropriate.

-  Add a drop down list that will allow the user to choose how many items per page he wants.