排序ObservableCollection绑定到MVVM中的DataGrid

问题描述:

我有一个DataGrid,我绑定到我的视图模型中的ObservableCollection,我需要能够对DataGrid进行排序时对集合进行排序,以便我可以在其他地方使用此排序顺序。我目前在ObvservableCollection上使用包装来支持排序。 DataGrid排序时,它只对显示的数据进行排序,而不排序集合中的基础数据。数据由一个整数列和一个字符串列组成,需要支持升序和降序排序。我还希望保持与标准DataGrid排序相同的用法,即单击列标题并在升序和降序之间切换。我对WPF比较陌生,所以我不知道数据和命令绑定的所有细节,但我认为会有办法完成我想要做的事情。这里是一个示例xaml来说明我的视图设置。排序ObservableCollection绑定到MVVM中的DataGrid

<DataGrid ItemsSource="{Binding mySource}" 
      Name="myDataGrid" 
      CanUserResizeRows="False" 
      AutoGenerateColumns="False" 
      HeadersVisibility="Column" > 
    <DataGrid.Columns> 

     <DataGridTemplateColumn Header="Header 1" CanUserSort="True" SortMemberPath="firstValue"> 
     <DataGridTemplateColumn.CellTemplate> 
      <DataTemplate> 
      <TextBlock Text="{Binding firstValue}" /> 
      </DataTemplate> 
     </DataGridTemplateColumn.CellTemplate> 
     </DataGridTemplateColumn> 

     <DataGridTemplateColumn Header="Header 2" Width="*" CanUserSort="True" SortMemberPath="secondValue"> 
     <DataGridTemplateColumn.CellTemplate> 
      <DataTemplate> 
      <TextBlock Text="{Binding secondValue}" /> 
      </DataTemplate> 
     </DataGridTemplateColumn.CellTemplate> 
     </DataGridTemplateColumn> 

    </DataGrid.Columns> 
</DataGrid> 

源数据的类型是这样的:现在

public class myType 
{ 
    public int firstValue { get; set; } 
    public string secondValue { get; set; } 

    // some functions and variables... 
} 

,就像我上面说的,我需要访问他们的有序集合中的项目,但它并不需要具体是一个ObservableCollection。只要我能访问集合中的项目,无论当前的顺序是什么,当我访问它们时,一切都很好。我想也许是一个ListCollectionView什么的。我也不希望集合在新项目添加到集合时重新排序。任何新项目都应该像正常情况一样添加到集合的末尾。

任何想法?

DataGrid使用基于数据源的底层ICollectionView,所以如果直接绑定ICollectionView可以访问排序值作为DataGrid将直接改变ICollectionView排序时。

小例子:

代码:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     // dummy data source/Your ObservableCollection 
     var yourObservableCollection = Enumerable.Range(0, 30) 
      .Select(i => new MyType { FirstValue = i, SecondValue = i.ToString() }); 

     // Create CollectionView based on the data you want to show 
     MySource = CollectionViewSource.GetDefaultView(yourObservableCollection); 
     InitializeComponent(); 
    } 

    public ICollectionView MySource { get; set; } 

    private void Button_Click_1(object sender, RoutedEventArgs e) 
    { 
     foreach (var item in MySource.OfType<MyType>()) 
     { 
      Console.WriteLine("MyType - First: {0}, Second: {1}", 
       item.FirstValue, 
       item.SecondValue); 
     } 
    } 
} 

public class MyType 
{ 
    public int FirstValue { get; set; } 
    public string SecondValue { get; set; } 
} 

的XAML:

<Window x:Class="WpfApplication8.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow"`enter code here` Name="UI" Width="262" Height="318"> 
    <Grid DataContext="{Binding ElementName=UI}"> 
    <DataGrid Name="myDataGrid" 
       ItemsSource="{Binding MySource}" 
       CanUserSortColumns="True" 
       Margin="0,0,0,37" /> 
    <Button Content="Print To Output Window" 
      HorizontalAlignment="Left" 
      VerticalAlignment="Bottom" 
      Margin="10,0,0,10" 
      Width="144" 
      Click="Button_Click_1"/> 
    </Grid> 
</Window> 
+0

我不得不修改这一点在我的MVVM的设置工作,但我得到它的工作。感谢ICollectionView的提示。 – climbak

您可以使用ICollectionView梳理现有的集合。据System.ComponentModel

下找到

的代码是这样

var collectionView = CollectionViewSource.GetDefaultView(ObservableCollection_Name); 
     collectionView.SortDescriptions.Add(new SortDescription("Your Property", ListSortDirection.Descending)); 

在你的GridView或ListView可以绑定在现有的ObservableCollection。无需更改。

我知道这是一个古老的问题,但当我遇到类似的问题时,我想努力找到答案,我想按照它在屏幕上显示的顺序打印/导出数据。虽然@ sa_ddam213的答案是正确的,但它需要一些适合MVVM模式的调整,所以希望这对其他人有用。要做到这一点首先添加到您的视图模型的ICollectionView(我相信这是由UI使用的相同数据结构):

private ObservableCollection<yourDataType> tableData = new ObservableCollection<yourDataType>(); // The DataGridknow was originally bound to this 
private ICollectionView tableDataWrapper; 

然后添加一个新的getter/setter您ICollectionView:

public ICollectionView TableDataWrapper 
{ 
    get { return this.tableDataWrapper; } 
    set 
    { 
     this.tableDataWrapper = value; 
     OnPropertyChanged("tableDataWrapper"); 
    } 
} 

而且在原始资料表二传手添加一行到每个表中的数据集时设置包装:

public ObservableCollection<yourDataType> TableData 
{ 
    get { return this.tableData; } 
    set 
    { 
     this.tableData = value; 
     this.TableDataWrapper = CollectionViewSource.GetDefaultView(tableData); // Add this 
     OnPropertyChanged("tableData"); 
    } 
} 

现在更新DataGrid的映射,所以它必然TableDataWrapper而不是TableData 我们访问数据的排序顺序:

this.TableDataWrapper.Cast<yourDataType>().ToList<yourDataType>() 

,或者如果你想把它当作一个ObservableCollection:

new ObservableCollection(this.TableDataWrapper.Cast<yourDataType>().ToList<yourDataType>())