Paging ListView using DataPager without using DataSource Control

If you have already used the ASP.NET ListView and DataPager controls, you know how easily you can display your data using custom templates and provide pagination functionality. You can do that in only few minutes. The ListView and DataPager controls work perfectly fine in combination with DataSource controls (SqlDataSource, LinqDataSource, ObjectDataSource etc.), however if you use them with custom data collection, without using Data Source controls, you may find some unexpected behavior and have to add some little more code to make it work.

Note: I saw question related to this issue asked multiple times in different asp.net forums, so I thought it would be nice to document it here.

Lets create a working demo together…

1. Create sample ASP.NET Web Application project, add new ASPX page.

2. Add ListView control and modify the markup so that you will end up having this:

        <asp:ListView ID="ListView1" runat="server">
        <LayoutTemplate>
            <ul>
                <asp:PlaceHolder ID="itemPlaceholder" runat="server" />
            </ul>
        </LayoutTemplate>
        <ItemTemplate>
            <li>
                <%# Eval("Name") %> (<%# Eval("Currency") %> <%# Eval("Price") %>)
            </li>
        </ItemTemplate>
        <EmptyDataTemplate>
            No data
        </EmptyDataTemplate>
        </asp:ListView>

The ListView control has three templates defined:

  • LayoutTemplate – where we define the way we want to represent our data. We have PlaceHolder where data from ItemTemplate will be placed. ListView recognizes this automatically.
  • ItemTemplate – where the ListView control will show the items from the data source. It makes automatically iterating over each item in the collection (same as any other data source control)
  • EmptyDataTemplate – If the collection has no data, this template will be displayed.

3. Add DataPager control and modify the markup in the following way:

        <asp:DataPager ID="lvDataPager1" runat="server" PagedControlID="ListView1" PageSize="5">
            <Fields>
                <asp:NumericPagerField ButtonType="Link" />
            </Fields>
        </asp:DataPager>


We add the DataPager control, associate it with the ListView1 control and add the PageSize property. After that, we need to define <Fields> where we put the field type and button type.

If we were binding from Data Source Control (SqlDataSource, LinqDataSource or any other…) this would be it and the ListView and DataPager would work perfectly fine. However, if we bind custom data collection to the ListView without using Data Source controls, we will have problems with the pagination.

Lets add custom data in our C# code and bind it to the ListView.

4. C# code adding custom data collection

- Define Product class

public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Currency { get; set; }
}

- Define method that will create List of products (sample data)

List<Product> SampleData()
{
    List<Product> p = new List<Product>();
    p.Add(new Product() { Name = "Microsoft Windows 7", Price = 70, Currency = "USD" });
    p.Add(new Product() { Name = "HP ProBook", Price = 320, Currency = "USD" });
    p.Add(new Product() { Name = "Microsoft Office Home", Price = 60, Currency = "USD" });
    p.Add(new Product() { Name = "NOKIA N900", Price = 350, Currency = "USD" });
    p.Add(new Product() { Name = "BlackBerry Storm", Price = 100, Currency = "USD" });
    p.Add(new Product() { Name = "Apple iPhone", Price = 400, Currency = "USD" });
    p.Add(new Product() { Name = "HTC myTouch", Price = 200, Currency = "USD" });            
    return p;
}

This method should be part of the ASPX page class (e.g. inside _Default page class if your page is Default.aspx)

- Bind the sample data to ListView on Page_Load

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        BindListView();
    }
}

void BindListView()
{
    ListView1.DataSource = SampleData();
    ListView1.DataBind();
}

Now, run the project and you should see the data displayed where only the first five items will be shown. The data pager should have two pages (1 2) and you will be able to click the second page to navigate to the last two items in the `collection.

Now, if you click on page 2, you will see it won’t display the last two items automatically, instead you will have to click again on page 2 to see the last two items. After, if you click on page 1, you will encounter another problem where the five items are displayed, but the data for the last two items in the ListView are shown (see print screen bellow)

 

If you notice in the previous two pictures, the behavior doesn’t seem to work properly. The problem here is that DataPager doesn’t know about current ListView page changing property. Therefore, we should explicitly set the DataPager Page Properties in the ListView’s PagePropertiesChanging event. Here is what we need to do:

1. Add OnPagePropertiesChanging event to ListView control

<asp:ListView ID="ListView1" runat="server" OnPagePropertiesChanging="ListView1_PagePropertiesChanging">

2. Implement the ListView1_PagePropertiesChanging method

protected void ListView1_PagePropertiesChanging(object sender, PagePropertiesChangingEventArgs e)
{
    //set current page startindex, max rows and rebind to false
    lvDataPager1.SetPageProperties(e.StartRowIndex, e.MaximumRows, false);

    //rebind List View
    BindListView();
}

Now, if you test the functionality, it should work properly.

Hope this was helpful.

Regards,
Hajan

20 Comments

Comments have been disabled for this content.