C# 有界数据更改后重新排序 WPF DataGrid
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11505283/
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
Re-sort WPF DataGrid after bounded Data has changed
提问by marc wellman
I am looking for a way to re-sortmy DataGridwhen the underlying data has changed.
我正在寻找一种在基础数据发生变化时重新排序我的方法。DataGrid
(The setting is quite standard: The DataGrid's ItemSourceproperty is bound to an ObservableCollection; The columns are DataGridTextColumns; The data inside the DataGrid reacts correctly on changes inside the ObservableCollection; Sorting works fine when clicked with the mouse)
(设置非常标准:DataGrid 的ItemSource属性绑定到ObservableCollection; 列是DataGridTextColumns; DataGrid 内的数据对 ObservableCollection 内的更改做出正确反应;用鼠标单击时排序工作正常)
Any ideas ?
有任何想法吗 ?
采纳答案by marc wellman
It took me the whole afternoon but I finally found a solutionthat is surprisingly simple, shortand efficient:
我花了整个下午,但我终于找到了一个非常简单、简短和高效的解决方案:
To control the behaviors of the UI control in question (here a DataGrid) one might simply use a CollectionViewSource. It acts as a kind of representative for the UI control inside your ViewModel without completely breaking the MVMM pattern.
要控制所讨论的 UI 控件的行为(此处为 a DataGrid),可以简单地使用CollectionViewSource. 它充当了 ViewModel 中 UI 控件的一种代表,而不会完全打破 MVMM 模式。
In the ViewModel declare both a CollectionViewSourceand an ordinary ObservableCollection<T>and wrap the CollectionViewSourcearound the ObservableCollection:
在 ViewModel 中声明 aCollectionViewSource和一个普通的,ObservableCollection<T>并将 包裹在CollectionViewSource周围ObservableCollection:
// Gets or sets the CollectionViewSource
public CollectionViewSource ViewSource { get; set; }
// Gets or sets the ObservableCollection
public ObservableCollection<T> Collection { get; set; }
// Instantiates the objets.
public ViewModel () {
this.Collection = new ObservableCollection<T>();
this.ViewSource = new CollectionViewSource();
ViewSource.Source = this.Collection;
}
Then in the View part of the application you have nothing else to do as to bind the ItemsSourceof the CollectionControlto the View property of the CollectionViewSourceinstead of directly to the ObservableCollection:
然后在应用程序的视图部分你没有事情做,因为绑定ItemsSource的CollectionControl到的View属性CollectionViewSource,而不是直接到ObservableCollection:
<DataGrid ItemsSource="{Binding ViewSource.View}" />
From this point on you can use the CollectionViewSourceobject in your ViewModel to directly manipulate the UI control in the View.
从现在开始,您可以使用CollectionViewSourceViewModel 中的对象直接操作 View 中的 UI 控件。
Sorting for example - as has been my primary problem - would look like this:
例如排序 - 正如我的主要问题 - 看起来像这样:
// Specify a sorting criteria for a particular column
ViewSource.SortDescriptions.Add(new SortDescription ("columnName", ListSortDirection.Ascending));
// Let the UI control refresh in order for changes to take place.
ViewSource.View.Refresh();
You see, very very simple and intuitive. Hope that this helps other people like it helped me.
你看,非常非常简单和直观。希望这能帮助其他像它一样帮助我的人。
回答by Justin Pihony
I cannot see any obviously easy ways, so I would try an Attached Behavior. It is a bit of a bastardization, but will give you what you want:
我看不到任何明显简单的方法,所以我会尝试附加行为。这有点混蛋,但会给你你想要的:
public static class DataGridAttachedProperty
{
public static DataGrid _storedDataGrid;
public static Boolean GetResortOnCollectionChanged(DataGrid dataGrid)
{
return (Boolean)dataGrid.GetValue(ResortOnCollectionChangedProperty);
}
public static void SetResortOnCollectionChanged(DataGrid dataGrid, Boolean value)
{
dataGrid.SetValue(ResortOnCollectionChangedProperty, value);
}
/// <summary>
/// Exposes attached behavior that will trigger resort
/// </summary>
public static readonly DependencyProperty ResortOnCollectionChangedProperty =
DependencyProperty.RegisterAttached(
"ResortOnCollectionChangedProperty", typeof (Boolean),
typeof(DataGridAttachedProperty),
new UIPropertyMetadata(false, OnResortOnCollectionChangedChange));
private static void OnResortOnCollectionChangedChange
(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
_storedDataGrid = dependencyObject as DataGrid;
if (_storedDataGrid == null)
return;
if (e.NewValue is Boolean == false)
return;
var observableCollection = _storedDataGrid.ItemsSource as ObservableCollection;
if(observableCollection == null)
return;
if ((Boolean)e.NewValue)
observableCollection.CollectionChanged += OnCollectionChanged;
else
observableCollection.CollectionChanged -= OnCollectionChanged;
}
private static void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (e.OldItems == e.NewItems)
return;
_storedDataGrid.Items.Refresh()
}
}
Then, you can attach it via:
然后,您可以通过以下方式附加它:
<DataGrid.Style>
<Style TargetType="DataGrid">
<Setter
Property="AttachedProperties:DataGridAttachedProperty.ResortOnCollectionChangedProperty"
Value="true"
/>
</Style>
</DataGrid.Style>
回答by sellmeadog
This is more for clarification than it is an answer, but WPF alwaysbinds to an ICollectionViewand not the source collection. CollectionViewSourceis just a mechanism used to create/retrieve the collection view.
这更多是为了澄清而不是答案,但 WPF始终绑定到一个ICollectionView而不是源集合。CollectionViewSource只是一种用于创建/检索集合视图的机制。
Here's a great resource about the topic which should help you make better use of collection views in WPF: http://bea.stollnitz.com/blog/?p=387
这是有关该主题的重要资源,可以帮助您更好地使用 WPF 中的集合视图:http: //bea.stollnitz.com/blog/?p= 387
Using CollectionViewSourcein XAML can actually simplify your code some:
CollectionViewSource在 XAML 中使用实际上可以简化您的代码:
<Window.Resources>
<CollectionViewSource Source="{Binding MySourceCollection}" x:Key="cvs">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="ColumnName" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
...
<DataGrid ItemsSource="{Binding Source={StaticResource cvs}}">
</DataGrid>
Some people argue that when following the MVVM pattern, the view model should always expose the collection view but in my opinion, it just depends on the use case. If the view model is never going to directly interact with the collection view, it's just easier to configure it in XAML.
有些人认为在遵循 MVVM 模式时,视图模型应该始终公开集合视图,但在我看来,这仅取决于用例。如果视图模型永远不会直接与集合视图交互,那么在 XAML 中配置它会更容易。
回答by DanW
For anyone else having this problem, this may get you started... If you have a collection of INotifyPropertyChanged items, you can use this instead of ObservableCollection - it will refresh when individual items in the collection change: note: since this flags the items as removed then readded (even though they aren't actually removed and added,) selections may get out of sync. It's good enough for my small personal projects, but it's not ready to release to customers...
对于遇到此问题的其他任何人,这可能会让您开始...如果您有 INotifyPropertyChanged 项目的集合,您可以使用它代替 ObservableCollection - 当集合中的单个项目更改时它会刷新:注意:因为这会标记项目删除然后重新读取(即使它们实际上没有被删除和添加,)选择可能会不同步。对于我的小型个人项目来说已经足够好了,但还没有准备好发布给客户......
public class ObservableCollection2<T> : ObservableCollection<T>
{
public ObservableCollection2()
{
this.CollectionChanged += ObservableCollection2_CollectionChanged;
}
void ObservableCollection2_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
foreach (object o in e.OldItems)
remove(o);
if (e.NewItems != null)
foreach (object o in e.NewItems)
add(o);
}
void add(object o)
{
INotifyPropertyChanged ipc = o as INotifyPropertyChanged;
if(ipc!=null)
ipc.PropertyChanged += Ipc_PropertyChanged;
}
void remove(object o)
{
INotifyPropertyChanged ipc = o as INotifyPropertyChanged;
if (ipc != null)
ipc.PropertyChanged -= Ipc_PropertyChanged;
}
void Ipc_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
NotifyCollectionChangedEventArgs f;
f = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, sender);
base.OnCollectionChanged(f);
f = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, sender);
base.OnCollectionChanged(f);
}
}
回答by AnjumSKhan
回答by Anthony Nichols
The answer by sellmeadog is either overly complicated or out of date. It's super simple. All you have to do is:
sellmeado 的答案要么过于复杂,要么已经过时。超级简单。您所要做的就是:
<UserControl.Resources>
<CollectionViewSource
Source="{Binding MyCollection}"
IsLiveSortingRequested="True"
x:Key="MyKey" />
</UserControl.Resources>
<DataGrid ItemsSource="{Binding Source={StaticResource MyKey} }" >...

