MVVM 分页 &排序 [英] MVVM paging & sorting

查看:17
本文介绍了MVVM 分页 &排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力寻找合适的解决方案来为符合 MVVM P&P 的 WPF DataGrid 实现排序和分页.

I am struggling with finding an adequate solution to impletmenting Sorting and Paging for a WPF DataGrid that conforms to the MVVM P&P.

以下示例说明了一种遵循 MVVM 实践的实现分页的有效方法,但是排序的自定义实现(一旦实现分页就需要)不遵循 MVVM:

The following example illustrates an effective way to implement paging which follows MVVM practices, but the custom implementation of sorting (which is required once you implement paging) does not follow MVVM:

http://www.eggheadcafe.com/tutorials/aspnet/8a2ea78b-f1e3-45b4-93ef-32b2d802ae17/wpf-datagrid-custom-pagin.aspx

我目前有一个绑定到 CollectionViewSource(在 XAML 中使用 GroupDescriptions 和 SortDescriptions 定义)的 DataGrid 绑定到我的 ViewModel 中的 ObservableCollection.一旦您通过限制 DataGrid 每页获取的项目数来实现分页,它就会破坏 CollectionViewSource 中定义的排序,因为它只对项目的子集进行排序.MVVM 下实现分页和排序的最佳方法是什么?

I currently have a DataGrid bound to a CollectionViewSource (defined in XAML with GroupDescriptions and SortDescritptions) bound to an ObservableCollection in my ViewModel. As soon as you implement Paging by limiting the number of items your DataGrid gets per page, it breaks the sorting defined in the CollectionViewSource because it is only sorting the subset of items. What is the best approach under MVVM to implement Paging and Sorting?

谢谢,

亚伦

推荐答案

前几天我写了一个 PagingController 类来帮助分页,所以你开始吧:

The other day I wrote a PagingController class to help with paging, so here you go:

您将不得不稍微清理一下源代码,因为要使用 MS Code Contracts,它们引用了来自 Prism 等的一些(非常基本的)实用工具.

You will have to clean up the sources a bit because the make some use of MS Code Contracts, they reference some (really basic) utility stuff from Prism, etc.

使用示例(代码隐藏 - ViewModel.cs):

Usage sample (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();
    }
}

使用示例(XAML - View.xaml):

Usage sample (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>

简短说明:

如您所见,ViewModel 并没有做太多事情.它保存代表当前页面的项目集合,并向视图公开一个 CollectionView(用于数据绑定)和一个 PagingController.然后它所做的就是在每次 PagingController 指示某些内容发生更改时更新集合中的数据项(因此在 CollectionView 中).当然,这意味着您需要一个方法,在给定起始索引、页面大小和 SortDescription[] 的情况下,返回由这些参数描述的数据片段.这是您业务逻辑的一部分,我没有在此处包含相关代码.

As you see, the ViewModel doesn't really do much. It keeps a collection of items representing the current page, and exposes a CollectionView (for data binding) and a PagingController to the View. Then all it does is update the data items in the collection (and consequently in the CollectionView) every time the PagingController indicates that something has changed. Of course this means that you need a method that, given a starting index, a page size, and a SortDescription[] returns the slice of data described by these parameters. This is part of your business logic, and I haven't included code for that here.

在 XAML 端,所有工作都是通过绑定到 PagingController 来完成的.我在这里展示了全部功能(绑定到 First/Prev/Next/Last 命令的按钮,TextBoxCurrentPage 的直接绑定,以及 ScrollBar 的绑定CurrentPage).通常,您不会同时使用所有这些.

On the XAML side all the work is done by binding to the PagingController. I have exposed the full functionality here (buttons bound to First/Prev/Next/Last commands, direct binding of a TextBox to CurrentPage, and binding of a ScrollBar to CurrentPage). Typically you will not use all of this at the same time.

这篇关于MVVM 分页 &amp;排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆