文章目录
- 前言
- 相关链接
- 代码仓库
- 项目配置(省略)
- 项目初始配置
- xaml
- viewModel
- Filter过滤
- 详细代码
- 展示结果
- 问题
- Linq过滤
- CollectionData
- xaml
- viewModel
- sql,这里用到数据库,就不展开了
- 总结
前言
我们这次详细了解一下列表通知的底层是怎么实现的
相关链接
十月的寒流
WPF 中如何制作 DataGrid 的分页功能
代码仓库
我为了方便展示源代码,我将代码提交到了代码仓库里面
B站【十月的寒流】对应课程的代码 Github仓库
项目配置(省略)
想要看的话看我前面的文章就可以了
项目初始配置
和我之前的代码差不多,详细的就看我的源码好了,我会用TabItem来简单说明的。这就是初始配置的代码了
xaml
<UserControl x:Class="DataGrid_Pagination.Views.Demo1View"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:DataGrid_Pagination.Views"mc:Ignorable="d" xmlns:hc="https://handyorg.github.io/handycontrol"xmlns:viewModels="clr-namespace:DataGrid_Pagination.ViewModels"d:DesignHeight="450" d:DesignWidth="800"><UserControl.DataContext><viewModels:Demo1ViewModel x:Name="ViewModel"/></UserControl.DataContext><DockPanel><hc:Pagination MaxPageCount="10"DockPanel.Dock="Bottom"Margin="4 7"PageIndex="5"IsJumpEnabled="True" /><DataGrid ItemsSource="{Binding CollectionData.Data}"></DataGrid></DockPanel>
</UserControl>
viewModel
namespace DataGrid_Pagination.ViewModels
{public partial class Demo1ViewModel : ObservableObject{public Demo1View Demo1View { get; set; }[ObservableProperty]private CollectionData<Student> collectionData = new CollectionData<Student>();public Demo1ViewModel(){CollectionData = new CollectionData<Student>() {Data = new Student().FakeMany(10)};CollectionData.Init();CollectionData.CollectionView.Refresh();}}
}
Filter过滤
详细代码
<UserControl x:Class="DataGrid_Pagination.Views.Demo2View"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:DataGrid_Pagination.Views"mc:Ignorable="d" xmlns:hc="https://handyorg.github.io/handycontrol"xmlns:viewModels="clr-namespace:DataGrid_Pagination.ViewModels"d:DesignHeight="450" d:DesignWidth="800"><UserControl.DataContext><viewModels:Demo2ViewModel x:Name="ViewModel"/></UserControl.DataContext><DockPanel><hc:Pagination MaxPageCount="{Binding PageCount}"DockPanel.Dock="Bottom"Margin="4 7"PageIndex="{Binding PageIndex,Mode=TwoWay}"IsJumpEnabled="True" /><DataGrid ItemsSource="{Binding CollectionData.Data}"></DataGrid></DockPanel>
</UserControl>
namespace DataGrid_Pagination.ViewModels
{public partial class Demo2ViewModel : ObservableObject{public Demo2View View { get; set; }[ObservableProperty]private CollectionData<Student> collectionData = new CollectionData<Student>();private int pageIndex = 1;public int PageIndex{get => pageIndex;set {SetProperty(ref pageIndex, value);CollectionData.CollectionView.Refresh();}}public readonly int PageSize = 10;[ObservableProperty]private int pageCount = 1;public Demo2ViewModel(){CollectionData = new CollectionData<Student>(){Data = new Student().FakeMany(150)};CollectionData.Binding();CollectionData.CollectionView.CollectionChanged += (s, e) =>{var count = CollectionData.Data.ToList().Count;PageCount = (int)Math.Ceiling((decimal)(count / PageSize));};CollectionData.CollectionView.Filter = (item) =>{if (!(item is Student)){throw new Exception("属性类型不为Student");}var index = CollectionData.Data.ToList().IndexOf((Student)item);return PageIndex == index / PageSize + 1;};CollectionData.CollectionView.Refresh();}}
}
展示结果
问题
小数据量没问题,但是大数据会出问题。因为主要的计算是indexOf和每个项的Filter。o(n)*o(n)=o(n^2),复杂度太高了。
Linq过滤
Linq过滤就是我们每次都更新CollectionView绑定的对象,触发更新
CollectionData
public partial class CollectionData<T>:ObservableObject where T : class{[ObservableProperty]private IEnumerable<T> data = new List<T>();public ICollectionView CollectionView { get; set; }public CollectionData() { }public void Binding(){CollectionView = CollectionViewSource.GetDefaultView(Data);}}
xaml
<UserControl x:Class="DataGrid_Pagination.Views.Demo3View"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:local="clr-namespace:DataGrid_Pagination.Views"mc:Ignorable="d"xmlns:hc="https://handyorg.github.io/handycontrol"xmlns:viewModels="clr-namespace:DataGrid_Pagination.ViewModels"d:DesignHeight="450"d:DesignWidth="800"><UserControl.DataContext><viewModels:Demo3ViewModel x:Name="ViewModel" /></UserControl.DataContext><DockPanel><hc:Pagination MaxPageCount="{Binding PageCount}"DockPanel.Dock="Bottom"Margin="4 7"PageIndex="{Binding PageIndex,Mode=TwoWay}"IsJumpEnabled="True" /><DataGrid ItemsSource="{Binding CollectionData.Data}"></DataGrid></DockPanel>
</UserControl>
viewModel
namespace DataGrid_Pagination.ViewModels
{public partial class Demo3ViewModel : ObservableObject{public Demo3View View { get; set; }[ObservableProperty]private CollectionData<Student> collectionData = new CollectionData<Student>();private int pageIndex = 1;public int PageIndex{get => pageIndex;set{SetProperty(ref pageIndex, value);CollectionData.CollectionView.Refresh();}}public readonly int PageSize = 10;[ObservableProperty]private int pageCount = 1;public readonly List<Student> Students = new Student().FakeMany(150).ToList();public Demo3ViewModel(){CollectionData = new CollectionData<Student>(){Data = Students.Take(PageSize),};CollectionData.Binding();CollectionData.CollectionView.CollectionChanged += (s, e) =>{var count = Students.Count;PageCount = (int)Math.Ceiling((decimal)(count / PageSize));CollectionData.Data = Students.Skip((PageIndex - 1) * PageSize).Take(PageSize);};}}
}
sql,这里用到数据库,就不展开了
总结
分页是我们最常用的功能,这次简单实现了分页的效果。HandyControl没有提供主动的分页,需要我们组合一下。详细代码可以看我的Github仓库。三种过滤我都写了。