文章目录
- 前言
- 相关链接
- 代码仓库
- 项目配置(省略)
- 项目初始配置
- 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仓库。三种过滤我都写了。