如何对 WPF DataGrid 进行分页?

Posted

技术标签:

【中文标题】如何对 WPF DataGrid 进行分页?【英文标题】:How can I paginate a WPF DataGrid? 【发布时间】:2010-10-21 13:08:30 【问题描述】:

如何在 wpf DataGrid 中设置分页?

【问题讨论】:

请在代码项目中查看post 【参考方案1】:

上面的代码项目文章非常适合使用 ADO 表完成此操作。虽然对于大多数应用程序来说,它可能工作得很好,而且很容易理解,但还有一种更“类似于 WPF-zen”的方式来做到这一点,那就是使用 CollectionViews。与上面的示例相比,使用 CollectionView 的优势在于,它在您放入网格中的数据方面更加通用(并不是说您不能使该示例更通用),并且非常适合使用通用的 WPF 数据绑定模型。如果您需要,它为您提供了一个支持常见操作(如排序、分组等)的地方。

我整理了一个非常简短的示例,说明绑定到 .NET 4.0 DataGrid 控件的几乎无法正常工作的 PagingCollectionView。虽然该示例本身非常简单,但它至少向您展示了如何开始,因为您有一个围绕实际数据集合的代理,您可以在该代理上执行诸如 MoveToNextPage 和 MoveToPreviousPage 之类的简单操作。

这是用于 Window 事件处理和 PagingCollectionView 的 C#:

using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;

namespace GridPagingExample

    public partial class MainWindow : Window
    
        private readonly PagingCollectionView _cview;

        public MainWindow()
        
            InitializeComponent();
            this._cview = new PagingCollectionView(
                new List<object>
                
                    new  Animal = "Lion", Eats = "Tiger" ,
                    new  Animal = "Tiger", Eats =  "Bear" ,
                    new  Animal = "Bear", Eats = "Oh my" ,
                    new  Animal = "Wait", Eats = "Oh my isn't an animal" ,
                    new  Animal = "Oh well", Eats = "Who is counting anyway" ,
                    new  Animal = "Need better content", Eats = "For posting on ***" 
                ,
                2
            );
            this.DataContext = this._cview;
        

        private void OnNextClicked(object sender, RoutedEventArgs e)
        
            this._cview.MoveToNextPage();
        

        private void OnPreviousClicked(object sender, RoutedEventArgs e)
        
            this._cview.MoveToPreviousPage();
        
    

    public class PagingCollectionView : CollectionView
    
        private readonly IList _innerList;
        private readonly int _itemsPerPage;

        private int _currentPage = 1;

        public PagingCollectionView(IList innerList, int itemsPerPage)
            : base(innerList)
        
            this._innerList = innerList;
            this._itemsPerPage = itemsPerPage;
        

        public override int Count
        
            get 
             
                if (this._innerList.Count == 0) return 0;
                if (this._currentPage < this.PageCount) // page 1..n-1
                
                    return this._itemsPerPage;
                
                else // page n
                
                    var itemsLeft = this._innerList.Count % this._itemsPerPage;
                    if (0 == itemsLeft)
                    
                        return this._itemsPerPage; // exactly itemsPerPage left
                    
                    else
                    
                        // return the remaining items
                        return itemsLeft;
                    
                
            
        

        public int CurrentPage
        
            get  return this._currentPage; 
            set
            
                this._currentPage = value;
                this.OnPropertyChanged(new PropertyChangedEventArgs("CurrentPage"));
            
        

        public int ItemsPerPage  get  return this._itemsPerPage;  

        public int PageCount
        
            get 
             
                return (this._innerList.Count + this._itemsPerPage - 1) 
                    / this._itemsPerPage; 
            
        

        private int EndIndex
        
            get
            
                var end = this._currentPage * this._itemsPerPage - 1;
                return (end > this._innerList.Count) ? this._innerList.Count : end;
            
        

        private int StartIndex
        
            get  return (this._currentPage - 1) * this._itemsPerPage; 
        

        public override object GetItemAt(int index)
        
            var offset = index % (this._itemsPerPage); 
            return this._innerList[this.StartIndex + offset];
        

        public void MoveToNextPage()
        
            if (this._currentPage < this.PageCount)
            
                this.CurrentPage += 1;
            
            this.Refresh();
        

        public void MoveToPreviousPage()
        
            if (this._currentPage > 1)
            
                this.CurrentPage -= 1;
            
            this.Refresh();
        
    

这是窗口的 XAML:

<Window x:Class="GridPagingExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Grid.Row="0">
            <Label Grid.Row="0" Margin="2">
                <Label.Content>
                    <Binding Path="CurrentPage">
                        <Binding.StringFormat>Current Page: 0</Binding.StringFormat>
                    </Binding>
                </Label.Content>
            </Label>
            <Button Content="Next" Click="OnNextClicked" Margin="2"/>
            <Button Content="Previous" Click="OnPreviousClicked" Margin="2"/>
        </StackPanel>
        <DataGrid ItemsSource="Binding" Grid.Row="1">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Animal" Width="*" Binding="Binding Animal"/>
                <DataGridTextColumn Header="Eats" Width="*" Binding="Binding Eats"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

您可以构建此 CollectionView 以支持更多功能,一些微不足道的功能,例如 MoveToLastPage 和 MoveToFirstPage,以及一些需要更多考虑您希望它如何表现的功能,例如排序。希望它是有帮助的。

【讨论】:

此外,Silverlight 有以下之一:msdn.microsoft.com/en-us/library/…,因此使用 Reflector 进行查看可能也是一个非常有用的示例。祝你好运! 但如果我的数据库中有 5 个数据并且我选择每页的项目为 2,那么在显示第 5 个项目时出现错误..我该如何解决?如果我有 8 个数据并且我将每页的项目选择为 3,则会发生同样的错误,我在显示最后两个项目时出现错误 当项目数小于 itemsPerPage 数时,此代码会出现索引超出范围异常。请参阅此处进行修复:***.com/questions/25300154/wpf-datagrid-pagination 另外,如果你想支持一个空的数据集,你需要在 Count 覆盖的开头进行这样的检查:“if (_innerList.Count == 0) return 0;” 如果您将基类替换为 ListCollectionView,您将获得巨大的性能提升(并且可能会减少错误) - 常规 CollectionViews 使用大量已弃用的行为,并且不再按原样实例化(参见 @ 987654323@).

以上是关于如何对 WPF DataGrid 进行分页?的主要内容,如果未能解决你的问题,请参考以下文章

WPF 实现 DataGrid/ListView 分页控件

WPF 实现 DataGrid/ListView 分页控件(转)

WPF 实现 DataGrid/ListView 分页控件(转)

WPF DataGrid如何分页、导出Excle、打印(急)

WPF DataGrid 如何对选择的多行进行删除

禁用 WPF MVVM 中 DataGrid 中自动生成的列的排序