2011-03-14 54 views
5

我正在与找到适当的解决方案来impletmenting排序和分页为符合所述MVVM P & P.MVVM寻呼&排序

以下示例的WPF数据网格挣扎示出实现分页下面MVVM的有效方法的做法,但排序的自定义实现(一旦你实现分页这是必需的)不遵循MVVM:

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

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

感谢,

亚伦

回答

12

一天,我写了一个PagingController类,以帮助分页,所以在这里你去:

你将不得不清理源比特b ecause在做一些使用MS代码契约,他们引用了一些(很基本的)工具的东西从棱镜等

使用Sample(代码隐藏 - 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(); 
    } 
} 

使用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> 

简短说明:

正如你看到的,视图模型并没有真正做多。它使表示当前页面项目的集合,并且暴露了CollectionView(用于数据绑定)和PagingController到视图。然后,它是所有更新的集合中的数据项(以及因此CollectionView中)每次PagingController表明,事情已经改变。当然,这意味着你需要的是,给定一个起始索引,页面大小,以及由这些参数来描述数据的SortDescription[]回报切片的方法。这是你业务逻辑的一部分,我没有在这里包含代码。

在XAML侧所有的工作都是通过结合PagingController完成。我已经公开了这里的全部功能(绑定到First/Prev/Next/Last命令的按钮,直接绑定TextBoxCurrentPage,并且绑定ScrollBar到)。通常你不会同时使用所有这些。

+0

非常感谢Jon,非常感谢! – Aaron 2011-03-17 15:42:19

+0

这对DataGrid调整大小(并因此更改可见元素的数量? – 2012-07-17 16:37:16

+0

@ChrisKlepeis:不是给定的,但您可以绑定到“PageSize”并注册为“PropertyChanged”,因此我没有看到当然,寻呼机并不是要有效地覆盖这种情况,所以perf就不会那么好。 – Jon 2012-07-17 17:25:19

4

你应该在你的ViewModel使用ListCollectionView类型的集合属性和网格绑定到它。这样,CollectionView定义将不会位于视图中,而是位于ViewModel中(它所属的位置),并且可以帮助您在ViewModel中轻松完成所有操作(无论是分页,排序还是过滤)

+2

感谢您的回应Elad! – Aaron 2011-03-17 15:43:14

+1

这是一个很好的答案。谢谢! – 2013-11-01 04:32:27