wpf 在 MVVM 中对绑定到 DataGrid 的 ObservableCollection 进行排序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18475883/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sort ObservableCollection bound to DataGrid in MVVM
提问by climbak
I have a DataGrid that I'm binding to an ObservableCollection in my view model and I need to be able to sort the collection when the DataGrid is sorted to so I can use this sorted order elsewhere. I'm currently using a wrapper on the ObvservableCollection to support sorting. When the DataGrid is sorted it only sorts the displayed data and not the underlying data in the collection. The data consists of one integer column and one string column and needs to support ascending and descending sort on both. I also want to maintain the same usage as the standard DataGrid sort where you click a column header and it toggles between ascending and descending sort. I'm relatively new to WPF so I don't know all the ins and outs of data and command binding, but I would think there would be a way to accomplish what I want to do. Here is a sample xaml to illustrate my view set up.
我有一个 DataGrid 绑定到我的视图模型中的 ObservableCollection,我需要能够在 DataGrid 排序时对集合进行排序,以便我可以在其他地方使用这个排序顺序。我目前在 ObvservableCollection 上使用包装器来支持排序。当 DataGrid 被排序时,它只对显示的数据而不是集合中的基础数据进行排序。数据由1个整数列和1个字符串列组成,需要同时支持升序和降序。我还希望保持与标准 DataGrid 排序相同的用法,在该排序中单击列标题并在升序和降序排序之间切换。我对 WPF 比较陌生,所以我不知道数据和命令绑定的所有来龙去脉,但我认为会有一种方法可以完成我想做的事情。
<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>
The source data is of a type something like:
源数据的类型类似于:
public class myType
{
public int firstValue { get; set; }
public string secondValue { get; set; }
// some functions and variables...
}
Now, like I said above, I need access to the items in the collection in their sorted order, but it does not need to specifically be an ObservableCollection. As long as I can iterate through the items in the collection in whatever the current order is when I access them, all is good. I was thinking maybe a ListCollectionView or something. I also don't want the collection to re-sort itself when new items are added to the collection. Any new items should just be added to the end of the collection as would normally happen.
现在,就像我上面所说的,我需要按排序顺序访问集合中的项目,但它不需要专门是 ObservableCollection。只要我可以在访问集合中的项目时以当前的顺序遍历它们,一切都很好。我在想也许是 ListCollectionView 之类的。当新项目添加到集合中时,我也不希望集合重新排序。任何新项目都应该像通常那样添加到集合的末尾。
Any ideas?
有任何想法吗?
回答by sa_ddam213
The DataGriduses an underlying ICollectionViewbased on the DataSource, so if you directly bind a ICollectionViewyou can access the sorted values as the DataGridwill directly change the ICollectionViewwhen sorting.
该DataGrid应用的底层ICollectionView基础数据源,所以如果你直接绑定ICollectionView,您可以访问排序值作为DataGrid将直接改变ICollectionView排序时。
Small Example:
小例子:
Code:
代码:
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:
Xml:
<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>
回答by stuicidle
I know this is an old question but I struggled to find an answer when I had a similar issue where I wanted to print/export the data in the same order it was displayed on the screen. Although @sa_ddam213 answer is correct it needs a bit of adjusting to fit the MVVM pattern, so hopefully this answer is of use to somebody else. To achieve this first add to your View Model an ICollectionView(I believe this is the same data structure used by the UI):
我知道这是一个老问题,但是当我遇到类似的问题时,我想以与屏幕上显示的顺序相同的顺序打印/导出数据时,我很难找到答案。尽管@sa_ddam213 答案是正确的,但它需要进行一些调整以适应 MVVM 模式,因此希望此答案对其他人有用。为了实现这一点,首先添加到您的视图模型中ICollectionView(我相信这与 UI 使用的数据结构相同):
private ObservableCollection<yourDataType> tableData = new ObservableCollection<yourDataType>(); // The DataGridknow was originally bound to this
private ICollectionView tableDataWrapper;
Then add a new Getter/Setter for your ICollectionView:
然后为您的 ICollectionView 添加一个新的 Getter/Setter:
public ICollectionView TableDataWrapper
{
get { return this.tableDataWrapper; }
set
{
this.tableDataWrapper = value;
OnPropertyChanged("TableDataWrapper");
}
}
And in your original TableData Setter add a line to set the wrapper each time the table data is set:
并在您的原始 TableData Setter 中添加一行以在每次设置表数据时设置包装器:
public ObservableCollection<yourDataType> TableData
{
get { return this.tableData; }
set
{
this.tableData = value;
this.TableDataWrapper = CollectionViewSource.GetDefaultView(tableData); // Add this
OnPropertyChanged("TableData");
}
}
Now update the DataGrid's Bindings so it is bound to TableDataWrapperrather than TableDataNow to access the data in the sorted order:
现在更新 DataGrid 的绑定,使其绑定到TableDataWrapper而不是TableDataNow 以按排序顺序访问数据:
this.TableDataWrapper.Cast<yourDataType>().ToList<yourDataType>()
or if you want it as an ObservableCollection:
或者如果你想要它作为ObservableCollection:
new ObservableCollection( this.TableDataWrapper.Cast<yourDataType>().ToList<yourDataType>() )
回答by Jyotirmaya Prusty
You can use ICollectionView to sort an existing collection. It is found under System.ComponentModel
您可以使用 ICollectionView 对现有集合进行排序。它位于 System.ComponentModel 下
The code goes like this
代码是这样的
var collectionView = CollectionViewSource.GetDefaultView(ObservableCollection_Name);
collectionView.SortDescriptions.Add(new SortDescription("Your Property", ListSortDirection.Descending));
In your GridView or ListView you can bind the existing ObservableCollection. No need to change.
在您的 GridView 或 ListView 中,您可以绑定现有的 ObservableCollection。没有必要改变。

