2011-03-14 47 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