none
Paging with a ListView RRS feed

  • Question

  • I'm having a hard time figuring out how to do paging in WPF using a ListView/GridView.

     

    Essentially, I have a collection of about 100 or so items in it. I'd like to lay out my UI with showing maybe 15-20 items at a time, and the ability to view the next 15 items (and previous as well). 

     

    The examples on the internet seem to be years old and not anything using built in features that I've seen.

     

    -Catch

    Saturday, October 30, 2010 6:12 PM

Answers

  • Here is a complete working Sample, download from all in one code framework (http://1code.codeplex.com/):

     

    MainWindow.xaml:

    <Window x:Class="CSWPFPaging.MainWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="WPF Paging Sample" Height="431" Width="579" Loaded="Window_Loaded">
      <Grid>
        <TextBlock Height="21" Margin="18,10,19,0" Name="textBlock1" VerticalAlignment="Top" 
              Text="This sample demonstrates how to page data in WPF."/>
        
        <ListView Margin="18,32,20,45" Name="listView1" ItemsSource="{Binding}">
          <ListView.View>
            <GridView>
              <GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" Width="50"/>
              <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="100"/>
              <GridViewColumn Header="Age" DisplayMemberBinding="{Binding Age}" Width="100"/>
              <GridViewColumn Header="Country" DisplayMemberBinding="{Binding Country}" Width="100"/>
            </GridView>
          </ListView.View>
        </ListView>
        
        <Button Height="23" HorizontalAlignment="Left" Margin="18,0,0,16" Name="btnFirst" 
            VerticalAlignment="Bottom" Width="75" Click="btnFirst_Click">First</Button>
        <Button Height="23" HorizontalAlignment="Left" Margin="115,0,0,16" Name="btnPrev" 
            VerticalAlignment="Bottom" Width="75" Click="btnPrev_Click">Previous</Button>
        <Button Height="23" Margin="213,0,269,16" Name="btnNext" 
            VerticalAlignment="Bottom" Click="btnNext_Click">Next</Button>
        <Button Height="23" HorizontalAlignment="Right" Margin="0,0,167,16" Name="btnLast" 
            VerticalAlignment="Bottom" Width="75" Click="btnLast_Click">Last</Button>
        
        <TextBlock Height="21" Margin="442,0,93,18" Name="tbCurrentPage" 
              VerticalAlignment="Bottom" />
        <TextBlock Height="21" HorizontalAlignment="Right" Margin="0,0,67,17" Name="textBlock3" 
              VerticalAlignment="Bottom" Width="20" Text="/"/>
        <TextBlock Height="21" HorizontalAlignment="Right" Margin="0,0,45,18" Name="tbTotalPage" 
              VerticalAlignment="Bottom" Width="28" />
      </Grid>
    </Window>
    
    

    MainWindow.xaml.CS:

    /************************************* Module Header **************************************\
    * Module Name: MainWindow.xaml.cs
    * Project:   CSWPFPaging
    * Copyright (c) Microsoft Corporation.
    * 
    * The sample demonstrates how to page data in WPF.
    * 
    * 
    * This source is subject to the Microsoft Public License.
    * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
    * All other rights reserved.
    * 
    * History:
    * * 12/02/2009 3:00 PM Zhi-Xin Ye Created
    */
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Collections.ObjectModel;
    
    namespace CSWPFPaging
    {
      /// <summary>
      /// Interaction logic for MainWindow.xaml
      /// </summary>
      public partial class MainWindow : Window
      {
        public MainWindow()
        {
          InitializeComponent();
        }
    
        CollectionViewSource view = new CollectionViewSource();
        ObservableCollection<Customer> customers = new ObservableCollection<Customer>();
        int currentPageIndex = 0;
        int itemPerPage = 20;
        int totalPage = 0;
    
        private void ShowCurrentPageIndex()
        {
          this.tbCurrentPage.Text = (currentPageIndex + 1).ToString();
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
          int itemcount = 107;
          for (int j = 0; j < itemcount; j++)
          {
            customers.Add(new Customer()
            {
              ID = j,
              Name = "item" + j.ToString(),
              Age = 10 + j,
              Country = "China"
            });
          }
    
          // Calculate the total pages
          totalPage = itemcount / itemPerPage;
          if (itemcount % itemPerPage != 0)
          {
            totalPage += 1;
          }
    
          view.Source = customers;
    
          view.Filter += new FilterEventHandler(view_Filter);
    
          this.listView1.DataContext = view;
          ShowCurrentPageIndex();
          this.tbTotalPage.Text = totalPage.ToString();
        }
    
        void view_Filter(object sender, FilterEventArgs e)
        {
          int index = customers.IndexOf((Customer)e.Item);
    
          if (index >= itemPerPage * currentPageIndex && index < itemPerPage * (currentPageIndex + 1))
          {
            e.Accepted = true;
          }
          else
          {
            e.Accepted = false;
          }
        }
    
        private void btnFirst_Click(object sender, RoutedEventArgs e)
        {
          // Display the first page
          if (currentPageIndex != 0)
          {
            currentPageIndex = 0;
            view.View.Refresh();
          }
          ShowCurrentPageIndex();
        }
    
        private void btnPrev_Click(object sender, RoutedEventArgs e)
        {
          // Display previous page
          if (currentPageIndex > 0)
          {
            currentPageIndex--;
            view.View.Refresh();
          }
          ShowCurrentPageIndex();
        }
    
        private void btnNext_Click(object sender, RoutedEventArgs e)
        {
          // Display next page
          if (currentPageIndex < totalPage - 1)
          {
            currentPageIndex++;
            view.View.Refresh();
          }
          ShowCurrentPageIndex();
        }
    
        private void btnLast_Click(object sender, RoutedEventArgs e)
        {
          // Display the last page
          if (currentPageIndex != totalPage - 1)
          {
            currentPageIndex = totalPage - 1;
            view.View.Refresh();
          }
          ShowCurrentPageIndex();
        }
      }
    }
    
    

     

    Customer.cs:

    /************************************* Module Header **************************************\
    * Module Name: MainWindow.xaml.cs
    * Project:   CSWPFPaging
    * Copyright (c) Microsoft Corporation.
    * 
    * The sample demonstrates how to page data in WPF.
    * 
    * 
    * This source is subject to the Microsoft Public License.
    * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
    * All other rights reserved.
    * 
    * History:
    * * 12/02/2009 3:00 PM Zhi-Xin Ye Created
    */
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace CSWPFPaging
    {
      class Customer
      {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public string Country { get; set; }
      }
    }
    
    

     


    -
    Saturday, October 30, 2010 9:58 PM
  • Hi,

    as far as I know there isn't. And I'd think that IList.indexof is to expensive to use (well, as long as you have only 100 items, you might not notice). What people seem to do is to use the LINQ skip() and take() methods in order to define a page.You could probably do this in a ViewModel.


    http://wpfglue.wordpress.com
    Sunday, October 31, 2010 1:10 PM

All replies

  • Here is a complete working Sample, download from all in one code framework (http://1code.codeplex.com/):

     

    MainWindow.xaml:

    <Window x:Class="CSWPFPaging.MainWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="WPF Paging Sample" Height="431" Width="579" Loaded="Window_Loaded">
      <Grid>
        <TextBlock Height="21" Margin="18,10,19,0" Name="textBlock1" VerticalAlignment="Top" 
              Text="This sample demonstrates how to page data in WPF."/>
        
        <ListView Margin="18,32,20,45" Name="listView1" ItemsSource="{Binding}">
          <ListView.View>
            <GridView>
              <GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" Width="50"/>
              <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="100"/>
              <GridViewColumn Header="Age" DisplayMemberBinding="{Binding Age}" Width="100"/>
              <GridViewColumn Header="Country" DisplayMemberBinding="{Binding Country}" Width="100"/>
            </GridView>
          </ListView.View>
        </ListView>
        
        <Button Height="23" HorizontalAlignment="Left" Margin="18,0,0,16" Name="btnFirst" 
            VerticalAlignment="Bottom" Width="75" Click="btnFirst_Click">First</Button>
        <Button Height="23" HorizontalAlignment="Left" Margin="115,0,0,16" Name="btnPrev" 
            VerticalAlignment="Bottom" Width="75" Click="btnPrev_Click">Previous</Button>
        <Button Height="23" Margin="213,0,269,16" Name="btnNext" 
            VerticalAlignment="Bottom" Click="btnNext_Click">Next</Button>
        <Button Height="23" HorizontalAlignment="Right" Margin="0,0,167,16" Name="btnLast" 
            VerticalAlignment="Bottom" Width="75" Click="btnLast_Click">Last</Button>
        
        <TextBlock Height="21" Margin="442,0,93,18" Name="tbCurrentPage" 
              VerticalAlignment="Bottom" />
        <TextBlock Height="21" HorizontalAlignment="Right" Margin="0,0,67,17" Name="textBlock3" 
              VerticalAlignment="Bottom" Width="20" Text="/"/>
        <TextBlock Height="21" HorizontalAlignment="Right" Margin="0,0,45,18" Name="tbTotalPage" 
              VerticalAlignment="Bottom" Width="28" />
      </Grid>
    </Window>
    
    

    MainWindow.xaml.CS:

    /************************************* Module Header **************************************\
    * Module Name: MainWindow.xaml.cs
    * Project:   CSWPFPaging
    * Copyright (c) Microsoft Corporation.
    * 
    * The sample demonstrates how to page data in WPF.
    * 
    * 
    * This source is subject to the Microsoft Public License.
    * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
    * All other rights reserved.
    * 
    * History:
    * * 12/02/2009 3:00 PM Zhi-Xin Ye Created
    */
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Collections.ObjectModel;
    
    namespace CSWPFPaging
    {
      /// <summary>
      /// Interaction logic for MainWindow.xaml
      /// </summary>
      public partial class MainWindow : Window
      {
        public MainWindow()
        {
          InitializeComponent();
        }
    
        CollectionViewSource view = new CollectionViewSource();
        ObservableCollection<Customer> customers = new ObservableCollection<Customer>();
        int currentPageIndex = 0;
        int itemPerPage = 20;
        int totalPage = 0;
    
        private void ShowCurrentPageIndex()
        {
          this.tbCurrentPage.Text = (currentPageIndex + 1).ToString();
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
          int itemcount = 107;
          for (int j = 0; j < itemcount; j++)
          {
            customers.Add(new Customer()
            {
              ID = j,
              Name = "item" + j.ToString(),
              Age = 10 + j,
              Country = "China"
            });
          }
    
          // Calculate the total pages
          totalPage = itemcount / itemPerPage;
          if (itemcount % itemPerPage != 0)
          {
            totalPage += 1;
          }
    
          view.Source = customers;
    
          view.Filter += new FilterEventHandler(view_Filter);
    
          this.listView1.DataContext = view;
          ShowCurrentPageIndex();
          this.tbTotalPage.Text = totalPage.ToString();
        }
    
        void view_Filter(object sender, FilterEventArgs e)
        {
          int index = customers.IndexOf((Customer)e.Item);
    
          if (index >= itemPerPage * currentPageIndex && index < itemPerPage * (currentPageIndex + 1))
          {
            e.Accepted = true;
          }
          else
          {
            e.Accepted = false;
          }
        }
    
        private void btnFirst_Click(object sender, RoutedEventArgs e)
        {
          // Display the first page
          if (currentPageIndex != 0)
          {
            currentPageIndex = 0;
            view.View.Refresh();
          }
          ShowCurrentPageIndex();
        }
    
        private void btnPrev_Click(object sender, RoutedEventArgs e)
        {
          // Display previous page
          if (currentPageIndex > 0)
          {
            currentPageIndex--;
            view.View.Refresh();
          }
          ShowCurrentPageIndex();
        }
    
        private void btnNext_Click(object sender, RoutedEventArgs e)
        {
          // Display next page
          if (currentPageIndex < totalPage - 1)
          {
            currentPageIndex++;
            view.View.Refresh();
          }
          ShowCurrentPageIndex();
        }
    
        private void btnLast_Click(object sender, RoutedEventArgs e)
        {
          // Display the last page
          if (currentPageIndex != totalPage - 1)
          {
            currentPageIndex = totalPage - 1;
            view.View.Refresh();
          }
          ShowCurrentPageIndex();
        }
      }
    }
    
    

     

    Customer.cs:

    /************************************* Module Header **************************************\
    * Module Name: MainWindow.xaml.cs
    * Project:   CSWPFPaging
    * Copyright (c) Microsoft Corporation.
    * 
    * The sample demonstrates how to page data in WPF.
    * 
    * 
    * This source is subject to the Microsoft Public License.
    * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
    * All other rights reserved.
    * 
    * History:
    * * 12/02/2009 3:00 PM Zhi-Xin Ye Created
    */
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace CSWPFPaging
    {
      class Customer
      {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public string Country { get; set; }
      }
    }
    
    

     


    -
    Saturday, October 30, 2010 9:58 PM
  • 1. Create a Customer class with properties of ID, Name, Age, Country, etc.

     

    2. Define a ListView with columns binding to each properties of the Customer object;

     

    3. Drag 4 buttons on to the MainWindow, which are for displaying first, previous,

       next, last page.

     

    4. Construct an ObservableCollection collection of Customer objects.

     

    5. Create a CollectionViewSource object and set source to the customer list.

     

    6. Handle the CollectionViewSource.Filter event to show data only in the current page.

     

            void view_Filter(object sender, FilterEventArgs e)

            {

                int index = customers.IndexOf((Customer)e.Item);

     

                if (index >= itemPerPage * currentPageIndex && index <

                    itemPerPage * (currentPageIndex + 1))

                {

                    e.Accepted = true;

                }

                else

                {

                    e.Accepted = false;

                }

            }

           

    7. Binding the CollectionViewSource object to the ListView.
    -
    Saturday, October 30, 2010 9:59 PM
  • Thanks for the examples and explanation, however I'm hoping there's a built in paging collection already there for you in WPF by now.
    Sunday, October 31, 2010 1:56 AM
  • Hi,

    as far as I know there isn't. And I'd think that IList.indexof is to expensive to use (well, as long as you have only 100 items, you might not notice). What people seem to do is to use the LINQ skip() and take() methods in order to define a page.You could probably do this in a ViewModel.


    http://wpfglue.wordpress.com
    Sunday, October 31, 2010 1:10 PM