是什么原因导致WPF ListCollectionView使用的定义排序重新排序它的项目?
题
考虑这个代码(类型的名字genericised为示例的目的):
// Bound to ListBox.ItemsSource
_items = new ObservableCollection<Item>();
// ...Items are added here ...
// Specify custom IComparer for this collection view
_itemsView = CollectionViewSource.GetDefaultView(_items)
((ListCollectionView)_itemsView).CustomSort = new ItemComparer();
当我设置的 CustomSort
, ,收集是按我所期望的。
但是我需要的数据重新进行排序本身在运行时响应不断变化的性质上 Item
.的 Item
类源自 INotifyPropertyChanged
我知道,酒店的火灾正确地作为我的数据的模板,更新值在屏幕上,只有分类逻辑是不是正在叫。
我也已经试图提高 INotifyPropertyChanged.PropertyChanged
通过一个空字符串中,看到如果一般的通知将引起的排序可以启动的。没有香蕉。
编辑 在应对肯特的建议,我想指出,排序的项目使用这种拥有相同的结果,即,收集各种各样一次但是 不不 重新排序的数据的变化:
_itemsView.SortDescriptions.Add(
new SortDescription("PropertyName", ListSortDirection.Ascending));
解决方案
我找到了 本文博士WPF 它开始了一个回答我的问题,然后讨论的性能产生影响的呼叫 Refresh
.一些关键的摘录:
不幸的是,刷新()方法,结果在一个完整的再生。当一个刷新的()发生内看,这就提出了一个CollectionChanged通知和用品的行动,如"重置"。该ItemContainerGenerator的列表框收到这种通知,并响应,通过放弃所有现有的视觉效果的项目。然后,它完全重新生成新项目的集装箱和视觉效果。
然后,他介绍了一个哈克的解决方法,提高性能。而不是叫刷新、删除、更改,然后再添加本项目。
我会认为它有可能是清单视图可以跟踪一个项目改变和知道重新定位,项单独内查看。
一种新的办法中引入了 .净3.5SP1 涉及接口 IEditableObject
提供的事务编辑通过数据定的模板的方法 BeginEdit()
, CancelEdit()
, , EndEdit()
.阅读 该文章 更多的信息。
编辑 作为 user346528指出, IEditableObject
不是在事实上新的中3.5SP1.它实际上看起来就像它已经在框架 因为1.0.
其他提示
由于接受的答案指示我,我能够强制单项重新定位代码
IEditableCollectionView collectionView = DataGrid.Items;
collectionView.EditItem(changedItem);
collectionView.CommitEdit();
其中 changedItem
是视图模型( ItemsSource
集合中的项目)。
这样你就不需要你的项目来实现任何接口,比如 IEditableObject
(在我看来,在某些情况下,这个接口非常复杂且难以实现)。
压缩旧帖子,但只创建一个继承自ListViewCollection和Overrides OnPropertyChanged的新集合类(对于IBindingList,ListChanged事件将包含ListChangedEventArgs参数中的属性更改)。并确保集合中的项实现并在属性更改(由您引发)时使用INotifyPropertyChange,否则集合将不会绑定到属性更改。
然后在此OnPropertyChanged方法中,发件人将成为项目。如果 - 并且仅当 - 导致度假胜地的属性被更改,则删除该项目,然后重新添加(如果添加它,则将其插入已排序的位置)。如果项目可用而不是删除/添加项目,则最好移动项目。同样,这也应该通过过滤(检查过滤器谓词)来完成。
不需要IEditableObject!如果你想编辑几个属性,然后完成编辑(比如编辑3个属性,然后在WinForm DataGridView中的另一行上选择),然后对它进行排序,这将是使其工作的正确方法。但很多时候,您可能希望在更改每个属性后使用该集合,而无需手动调用BeginEdit / EndEdit。 IEditableObject,btw,存在于.NET 2.0框架中,并不是.NET 3.5的新手(如果您阅读Dr的文章)。
注意:使用BeginEdit()和EndEdit()以及对同一项目进行多次编辑时可能会出现问题 - 除非您增加(对于true)/减量(对于false)整数而不是设置布尔值!记得增加/减少一个整数,以便真正知道编辑完成的时间。
保持永久排序的列表非常耗时且容易出错(如果强制排序插入,它可能会破坏插入协定),并且只能在某些位置使用,例如ComboBoxes。在任何网格上,这是一个非常糟糕的主意,因为更改一行将导致它从用户当前位置下撤出。
Public Class ListView
Inherits ListCollectionView
Protected Overrides Sub OnPropertyChanged(sender As Object, e As PropertyChangedEventArgs)
' Add resorting/filtering logic here.
End Sub
End Class
与Jesse Johnsons ObjectListView类似的集合上的最佳示例是Jesse Johnsons ObjectListView,尽管这是特定于.NET 2.0的(IBindingList而不是INotifyCollectionChanged / ObservableCollection / ListCollectionView)并且使用非常严格的许可证。他的博客在完成这项工作方面可能仍然非常有价值。
编辑:
忘记添加Sender将是您需要使用的项目,并且您将需要使用e.PropertyName来确定它是否在SortDescriptions中。如果不是,则对该属性的更改将不会导致需要度假村。如果e.PropertyName为Nothing,则它就像刷新一样,其中许多属性可能已经改变并且应该进行求助。
要确定是否需要过滤,只需通过FilterPredicate运行它,并在需要时将其删除。过滤比分拣要便宜得多。
希望有帮助,
TamusJRoyce
鉴于您正在使用自定义排序, ListCollectionView
无法知道应触发刷新的标准。因此,您需要自己在集合视图上调用 Refresh()
。