Using DataPager and ListView Controls with a Custom Data Source in the ASP.NET
DataPager is a new server control in ASP.NET 3.5 that makes the data paging easier as a built-in feature. The necessity for a customizable data pager control has been a request by developers for some years and ASP.NET 3.5 comes with this solution.
Even though DataPager control is limited to be used with ListView server control and there are also some limitations in customizing its behavior but it’s still a great way to accomplish data paging in a short and easy way.
As many other data controls in the ASP.NET, you can use ListView with different data source controls. There isn’t any special point about this in general except that you may stick with using these DataPager and ListView controls in conjunction with a custom data source programmatically.
In this post I want to repeat the known story about using DataPager and ListView with a built-in .NET data source and then talk about an issue that will come into the play when you want to use a custom data source.
First let me show you how to bind a ListView to a built-in data source control like XmlDataSource and use DataPager to enable paging among its data. To do this, I create a web form and add three controls to the page: an XmlDataSource that uses my RSS feed as its data file, a ListView control that uses this XmlDataSource as its data source and displays my most recent post titles and a DataPager control that pages among data in the ListView. This control uses a QueryStringField attribute to link to pages using query string parameter rather than internal paging. It also has a PageSize attribute that is set to 5 in order to display this number of items in a page.
DataPager has three types of <Field /> child elements that you can use to customize the behavior of paging and I factor them here. There are many resources about DataPager control to learn about its details.
So here is the ASPX code for this simple data binding scenario:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="DataPagerSample._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Using DataPager and ListView Controls with a Custom Data Source</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:DataPager ID="dataPager" runat="server" PagedControlID="listItems" QueryStringField="page"
PageSize="5">
<Fields>
<asp:NumericPagerField />
</Fields>
</asp:DataPager>
<br />
<asp:ListView ID="listItems" runat="server" DataSourceID="xmlDataSource">
<LayoutTemplate>
<asp:PlaceHolder runat="server" ID="itemPlaceholder" />
</LayoutTemplate>
<ItemTemplate>
<h3>
<a href="<%# XPath("guid") %>">
<%# XPath("title") %></h3>
</a> on
<%# XPath("pubDate")%>
</ItemTemplate>
<ItemSeparatorTemplate>
<hr />
</ItemSeparatorTemplate>
</asp:ListView>
<asp:XmlDataSource ID="xmlDataSource" runat="server" DataFile="http://feeds.nayyeri.net/keyvan"
XPath="rss/channel/item"></asp:XmlDataSource>
</div>
</form>
</body>
</html>
Now let me use a custom data source to bind my ListView programmatically. Before implementing this part, I need some mechanisms to fetch data from my feed and make them suitable for my data binding.
First I create a class called FeedFetcher that contains a single GetFeedItems function and it retrieves most recent blog posts from my feed using WCF Syndication framework. It returns a list of SyndicationItem objects that I’ll use as a data source for my ListView.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ServiceModel.Syndication;
using System.Xml;
namespace DataPagerSample.Components
{
public static class FeedFetcher
{
public static List<SyndicationItem> GetFeedItems(string feedUrl)
{
var rssReader = XmlReader.Create(feedUrl);
var rssFeed = SyndicationFeed.Load(rssReader);
return rssFeed.Items.ToList<SyndicationItem>();
}
}
}
Now I go back and create a new page with a ListView and a DataPager but this time I set the data source for my ListView control programmatically and use this list of SyndicationItem objects as my data source.
The ASPX code for this page looks like this:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default2.aspx.cs" Inherits="DataPagerSample.Default2" %>
<%@ Import Namespace="System.ServiceModel.Syndication" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Using DataPager and ListView Controls with a Custom Data Source</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:DataPager ID="dataPager" runat="server" PagedControlID="listItems" QueryStringField="page"
PageSize="5">
<Fields>
<asp:NumericPagerField />
</Fields>
</asp:DataPager>
<br />
<asp:ListView ID="listItems" runat="server">
<LayoutTemplate>
<asp:PlaceHolder runat="server" ID="itemPlaceholder" />
</LayoutTemplate>
<ItemTemplate>
<h3>
<a href="<%# Eval("Id") %>">
<%# ((TextSyndicationContent)Eval("Title")).Text %>
</a>
</h3>
on
<%# Eval("PublishDate")%>
</ItemTemplate>
<ItemSeparatorTemplate>
<hr />
</ItemSeparatorTemplate>
</asp:ListView>
</div>
</form>
</body>
</html>
And the code-behind is as simple as the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using DataPagerSample.Components;
using System.ServiceModel.Syndication;
namespace DataPagerSample
{
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
BindData();
}
private void BindData()
{
var items = FeedFetcher.GetFeedItems("http://feeds.nayyeri.net/keyvan");
this.listItems.DataSource = items;
this.listItems.DataBind();
}
}
}
This gives me an output similar to the output with the XmlDataSource.
This is fine but the problem appears when you navigate to other pages such as the second page because you still see data items for the first page.
This is weird! Most likely you expected to see the correct output from this control since I didn’t do anything except changing my data source. I wrestled with this issue for half an hour last week and couldn’t guess any solution. After some searches, I finally could find a forum post on ASP.NET forums that was talking about the issue with a not straightforward solution. I tried to work around and develop it to a very simple solution that I present here.
All you need to do is, adding a PageProeprtiesChanging event handler for your ListView control and there you should set the new page properties for your ListView and rebind your data.
Thus I can update my ASPX code with adding a new OnPagePropertiesChanging event for ListView control as follows:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default2.aspx.cs" Inherits="DataPagerSample.Default2" %>
<%@ Import Namespace="System.ServiceModel.Syndication" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Using DataPager and ListView Controls with a Custom Data Source</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:DataPager ID="dataPager" runat="server" PagedControlID="listItems" QueryStringField="page"
PageSize="5">
<Fields>
<asp:NumericPagerField />
</Fields>
</asp:DataPager>
<br />
<asp:ListView ID="listItems" runat="server" OnPagePropertiesChanging="listItems_PagePropertiesChanging">
<LayoutTemplate>
<asp:PlaceHolder runat="server" ID="itemPlaceholder" />
</LayoutTemplate>
<ItemTemplate>
<h3>
<a href="<%# Eval("Id") %>">
<%# ((TextSyndicationContent)Eval("Title")).Text %>
</a>
</h3>
on
<%# Eval("PublishDate")%>
</ItemTemplate>
<ItemSeparatorTemplate>
<hr />
</ItemSeparatorTemplate>
</asp:ListView>
</div>
</form>
</body>
</html>
And the code-behind should be updated to handle this event as well.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using DataPagerSample.Components;
using System.ServiceModel.Syndication;
namespace DataPagerSample
{
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
BindData();
}
private void BindData()
{
var items = FeedFetcher.GetFeedItems("http://feeds.nayyeri.net/keyvan");
this.listItems.DataSource = items;
this.listItems.DataBind();
}
protected void listItems_PagePropertiesChanging(object sender, PagePropertiesChangingEventArgs e)
{
this.dataPager.SetPageProperties(e.StartRowIndex, e.MaximumRows, false);
BindData();
}
}
}
This can simply solve the issue and show the correct data for each page.
I don’t know if this can be considered as an issue for DataPager and ListView controls or not but I’m pretty sure this could be as an internal part for these controls somehow. Having the first behavior in mind, this behavior is not expected for anyone, though!
Finally you can download the source code sample for this post.
[advertisement] Axosoft OnTime 2008 is four developer tools in one: bug tracking, project wiki, feature management, and help desk. It manages your development process so developers can focus on coding. Installed or Hosted – Free Single-user license -- Free 30-day team trial.
11 Comments : 08.25.08
Feedbacks
@Tim:
Thank you, Tim! You are very welcome and I hope this post can help you one day :-)
Pingback from Dew Drop - August 26, 2008 | Alvin Ashcraft's Morning Dew
oh, thank you so much, i has been searching for this solution long time d, is working for me.....
Hey great work and great stuff.....Thanks for the examples provided..Appreciable work buddy...Keep it up..
Thanks for your helping, It's useful for me. And can you answer for me this question? How to get the total of page of datapager?
Hi Mate.
Your article is great. I'm just thinking to replace DataPager control by repeater control because I can't figure out how to use DataPager at codebehind. Luckly I find this. It helps me a lot
Eric
Thanks a lot.
I am confused with is problem more than 2 days.
It is very help to me.
Nice example... and here is another way....
The nice thing belwo is it is within your Listview... Looks good when it's shown on the screen...
you can put tha dapager control in the listview self in the page (in the layoutemplate) like this...
<div class="pager">
<asp:DataPager ID="pagerBottom" runat="server" PagedControlID="listviewControlName" QueryStringField="page" PageSize="10" >
<Fields>
<asp:NextPreviousPagerField
ButtonCssClass="command"
FirstPageText="«" PreviousPageText="‹"
RenderDisabledButtonsAsLabels="true"
ShowFirstPageButton="true" ShowPreviousPageButton="true"
ShowLastPageButton="false" ShowNextPageButton="false"
/>
<asp:NumericPagerField
ButtonCount="7" NumericButtonCssClass="command" CurrentPageLabelCssClass="current" NextPreviousButtonCssClass="command"
/>
<asp:NextPreviousPagerField
ButtonCssClass="command"
LastPageText="»" NextPageText="›"
RenderDisabledButtonsAsLabels="true"
ShowFirstPageButton="false" ShowPreviousPageButton="false"
ShowLastPageButton="true" ShowNextPageButton="true"
/>
</Fields>
</asp:DataPager>
and in your code-behind in PagePropertiesChaningEventhandler:
==========================================
protected void listViewControlName_PagePropertiesChanging(object sender, PagePropertiesChangingEventArgs e)
{
DataPager dpBottom;
dpBottom = ((ListView)sender).FindControl("pagerBottom") as DataPager;
dpBottom.SetPageProperties(e.StartRowIndex, e.MaximumRows, false);
lvPallets.DataBind();
FillData();
}
#endregion
cheers,
mesut demir
Hi Keyvan
Your code example solved my problem. You are heaven sent!
Tesekkur Ederim!
Selam.
In the past 3.5 years of blogging, I haven’t had such best pick up collections in the end of the year, but now that everybody is writing one, why shouldn’t I write my own?! Collecting this list, I could realize some interesting facts that completely changed

#1
Tim Laughlin
08.25.2008 @ 1:29 PM
You find the best stuff to cover. These types of articles are great! I don't need to this today. But I am sure I will, so off the bookmarks for now. But in advance, thanks for the great info.