Aar*_*ron 6 sorting wpf paging datagrid mvvm
我正在努力寻找一个适当的解决方案来实现符合MVVM P&P的WPF DataGrid的排序和分页.
以下示例说明了实现按照MVVM实践进行的分页的有效方法,但排序的自定义实现(在实现分页后需要)不遵循MVVM:
我目前有一个DataGrid绑定到一个CollectionViewSource(在XAML中使用GroupDescriptions和SortDescritptions定义)绑定到我的ViewModel中的ObservableCollection.一旦通过限制DataGrid每页获取的项目数来实现Paging,它就会破坏CollectionViewSource中定义的排序,因为它只对项目的子集进行排序.MVVM下实施分页和排序的最佳方法是什么?
谢谢,
亚伦
Jon*_*Jon 13
前几天我写了一个PagingController类来帮助分页,所以在这里你去:
你需要清理一下这些资源,因为它们使用了MS Code Contracts,它们引用了Prism等的一些(非常基本的)实用程序.
用法示例(codebehind - ViewModel.cs):
private const int PageSize = 20;
private static readonly SortDescription DefaultSortOrder = new SortDescription("Id", ListSortDirection.Ascending);
private readonly ObservableCollection<Reservation> reservations = new ObservableCollection<Reservation>();
private readonly CollectionViewSource reservationsViewSource = new CollectionViewSource();
public ViewModel()
{
this.reservationsViewSource.Source = this.reservations;
var sortDescriptions = (INotifyCollectionChanged)this.reservationsViewSource.View.SortDescriptions;
sortDescriptions.CollectionChanged += this.OnSortOrderChanged;
// The 5000 here is the total number of reservations
this.Pager = new PagingController(5000, PageSize);
this.Pager.CurrentPageChanged += (s, e) => this.UpdateData();
this.UpdateData();
}
public PagingController Pager { get; private set; }
public ICollectionView Reservations
{
get { return this.reservationsViewSource.View; }
}
private void UpdateData()
{
var currentSort = this.reservationsViewSource.View.SortDescriptions.DefaultIfEmpty(DefaultSortOrder).ToArray();
// This is the "fetch the data" method, the implementation of which
// does not directly interest us for this example.
var data = this.crsService.GetReservations(this.Pager.CurrentPageStartIndex, this.Pager.PageSize, currentSort);
this.reservations.Clear();
this.reservations.AddRange(data);
}
private void OnSortOrderChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add) {
this.UpdateData();
}
}
Run Code Online (Sandbox Code Playgroud)
使用示例(XAML - View.xaml):
<DataGrid ... ItemSource="{Binding Reservations}" />
<!-- all the rest is UI to interact with the pager -->
<StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="4">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="FontFamily" Value="Webdings" />
<Setter Property="Width" Value="60" />
<Setter Property="Margin" Value="4,0,4,0" />
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="4,0,4,0" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="4,0,4,0" />
<Setter Property="Width" Value="40" />
</Style>
</StackPanel.Resources>
<Button Content="9" Command="{Binding Path=Pager.GotoFirstPageCommand}" />
<Button Content="3" Command="{Binding Path=Pager.GotoPreviousPageCommand}" />
<TextBlock Text="Page" />
<TextBox Text="{Binding Path=Pager.CurrentPage, ValidatesOnExceptions=True}" />
<TextBlock Text="{Binding Path=Pager.PageCount, StringFormat=of {0}}" />
<Button Content="4" Command="{Binding Path=Pager.GotoNextPageCommand}" />
<Button Content=":" Command="{Binding Path=Pager.GotoLastPageCommand}" />
</StackPanel>
<ScrollBar Orientation="Horizontal" Minimum="1" Maximum="{Binding Path=Pager.PageCount}" Value="{Binding Path=Pager.CurrentPage}"/>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)
简短说明:
如您所见,ViewModel并没有真正做多少.它保留表示当前页面的项目集合,并向View 公开CollectionView(用于数据绑定)和a PagingController.然后它所做的就是CollectionView每次PagingController指示某些内容发生变化时更新集合中的数据项(并因此更新).当然,这意味着您需要一个方法,给定起始索引,页面大小,并SortDescription[]返回这些参数描述的数据切片.这是您的业务逻辑的一部分,我在这里没有包含代码.
在XAML方面,所有工作都是通过绑定到PagingController.我已经暴露在这里的全部功能(绑定到一/上一页/下一页/尾的命令,直接绑定的按钮TextBox来CurrentPage,和一个结合ScrollBar到CurrentPage).通常,您不会同时使用所有这些.
您应该ListCollectionView在 ViewModel 中使用类型的集合属性,并将 Grid 绑定到它。这样,CollectionView 定义就不会位于 View 中,而是位于 ViewModel(它所属的位置)中,这将帮助您在 ViewModel 中轻松进行所有想要的操作(无论是分页、排序还是过滤)