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

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

问题描述

我正在努力寻找一种适用于符合MVVM P& P的WPF DataGrid的排序和分页的适当解决方案。



以下示例说明了一个有效的实现按照MVVM实践的分页的方法,但排序的自定义实现(在实现分页之后是必需的)不遵循MVVM:



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



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



感谢,



Aaron

解决方案

有一天我写了一个 PagingController 类来帮助分页,所以在这里go:





您将不得不清理资源,因为使用MS代码合同,他们引用了一些(真正基本的)实用程序从Prism等。 p>

使用示例(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;

// 5000这里是保留总数
this.Pager = new PagingController(5000,PageSize);
this.Pager.CurrentPageChanged + =(s,e)=> this.UpdateData();

this.UpdateData();

}

public PagingController Pager {get;私人集合}

public ICollectionView Reservations
{
get {return this.reservationsViewSource.View; }
}

private void UpdateData()
{
var currentSort = this.reservationsViewSource.View.SortDescriptions.DefaultIfEmpty(DefaultSortOrder).ToArray();

//这是获取数据的方法,其中
//的实现并不直接关系到我们的这个例子。
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 ):

 < DataGrid ... ItemSource ={Binding Reservations}/> 

<! - 其余的都是与寻呼机交互的UI - >
< StackPanel>
< StackPanel Orientation =Horizo​​ntalHorizo​​ntalAlignment =CenterMargin =4>
< StackPanel.Resources>
< Style TargetType ={x:Type Button}>
< Setter Property =FontFamilyValue =Webdings/>
< Setter属性=宽度值=60/>
< Setter Property =MarginValue =4,0,4,0/>
< / Style>
< Style TargetType ={x:Type TextBlock}>
< Setter Property =MarginValue =4,0,4,0/>
< Setter Property =VerticalAlignmentValue =Center/>
< / Style>
< Style TargetType ={x:Type TextBox}>
< Setter Property =MarginValue =4,0,4,0/>
< Setter Property =WidthValue =40/>
< / Style>
< /StackPanel.Resources>
< Button Content =9Command ={Binding Path = Pager.GotoFirstPageCommand}/>
< Button Content =3Command ={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 =4Command ={Binding Path = Pager.GotoNextPageCommand}/>
< Button Content =:Command ={Binding Path = Pager.GotoLastPageCommand}/>
< / StackPanel>
< ScrollBar Orientation =Horizo​​ntalMinimum =1Maximum ={Binding Path = Pager.PageCount}Value ={Binding Path = Pager.CurrentPage}/>
< / StackPanel>

简短说明:



如您所见,ViewModel并没有真正做得太多。它保存代表当前页面的项目的集合,并公开一个 CollectionView (用于数据绑定)和一个 PagingController 风景。那么所有这些都是每次 PagingController 指示时更新集合中的数据项(并因此在 CollectionView 中)有事情发生了变化。当然,这意味着您需要一种方法,给定起始索引,页面大小和 SortDescription [] 返回由这些参数描述的数据片段。这是您的业务逻辑的一部分,我没有在这里添加代码。



在XAML端,所有的工作都是通过绑定到$ $ c> PagingController 。我已经暴露了这里的全部功能(按钮绑定到First / Prev / Next / Last命令,直接绑定一个 TextBox CurrentPage ,并将 ScrollBar 绑定到 CurrentPage )。通常你不会同时使用所有这些。


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

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

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?

Thanks,

Aaron

解决方案

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

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.

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

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>

Short explanation:

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.

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天全站免登陆