增加WPF的ObservableCollection性能
目前我有两个WPF列表框模仿了以下功能增加WPF的ObservableCollection性能
我使用2个ObservableCollections,让用户选择他们需要的任何物品(灵活性是关键在这里)。主要问题是我有成千上万项目被分组在两个列表框中。总的来说,所有的设计作品都很好(有几十个项目),但是我的绊脚石是当屏幕冻结时(用于在不同线程上运行的时间),用户从左到右复制所有可用项目时。
看着ObservableCollection它缺少一个AddRange方法,并且在互联网上有各种实现可用。我也知道,CollectionChanged事件被不必要地解雇,因为每个项目都被复制到可怕的性能上。
这很可能是因为我不得不允许用户从将来超过10000个项目组中选择,这听起来像一个糟糕的主意,但由于列表框(CollectionViewSource)上的分组非常有效但有副作用切换关虚拟化的两个列表框
当数据绑定到ObservableCollection时加载带有数千项目的列表框时,我该怎么做才能提高性能?有没有可以推荐的AddRange类型实现?是我在这里唯一的选择在后台线程上运行这个看起来很昂贵的因为我不从数据库加载数据?
我已经删除了CollectionViewSource和分组,并且这些项目以1/2秒的速度被复制,但由于虚拟化不适用于分组,因此分组可能需要一分钟。
我需要决定是否使用CollectionViewSource
collectionviewsource在初始绑定发生时有效地工作,但在运行时效率非常低下。 我现在在使用LINQ的代码中进行排序/筛选 – Vault 2009-09-28 09:54:13
这是怎么回答的? – 2016-11-14 18:21:56
您可能会继承ObservableCollection<T>
(或直接执行INotifyCollectionChanged
)以添加BeginUpdate
和EndUpdate
方法。在调用BeginUpdate
和EndUpdate
之间进行的更改将排队,然后合并为一个(或若有单独范围存在若干个)NotifyCollectionChangedEventArgs
对象,调用EndUpdate
时将传递到CollectionChanged
事件的处理程序。
据我所知,WPF控件不支持集合的范围更新,并且当他们在一个CollectionChanged事件中收到多个项目时引发异常。 – 2009-11-26 23:34:27
WTF?!为什么提供能够在事件参数中指定多个项目(如果它们不支持它)?我已经实现了我的答案中描述的集合,但没有时间实际测试它......我刚刚做了,而且看起来你是对的:(所以我的集合不能用于绑定场景.. 。 – 2009-11-26 23:58:26
不能在WPF 4.0中工作:( – 2009-11-27 00:03:19
我无法抗拒回答这个。我认为你不会再需要这个答案,但也许有人可以使用它。不要想太多(不要使用这个多线程(这会使事情容易出错并且不必要的复杂,只能使用线程进行硬计算/ IO),所有这些不同的操作类型都会使缓冲变得非常困难。最烦人的部分是,如果您删除或添加10000个项目,您的应用程序(列表框)将非常忙于处理由ObservableCollection引发的事件。此事件已支持多个项目。因此.....
您可以缓冲项目直到它改变动作为止,所以添加动作将被缓冲,并且如果'用户'改变动作或刷新动作,将会以批处理形式提出。 还没有测试它,但你可以做这样的事情:
// Written by JvanLangen
public class BufferedObservableCollection<T> : ObservableCollection<T>
{
// the last action used
public NotifyCollectionChangedAction? _lastAction = null;
// the items to be buffered
public List<T> _itemBuffer = new List<T>();
// constructor registeres on the CollectionChanged
public BufferedObservableCollection()
{
base.CollectionChanged += new NotifyCollectionChangedEventHandler(ObservableCollectionUpdate_CollectionChanged);
}
// When the collection changes, buffer the actions until the 'user' changes action or flushes it.
// This will batch add and remove actions.
private void ObservableCollectionUpdate_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// if we have a lastaction, check if it is changed and should be flush else only change the lastaction
if (_lastAction.HasValue)
{
if (_lastAction != e.Action)
{
Flush();
_lastAction = e.Action;
}
}
else
_lastAction = e.Action;
_itemBuffer.AddRange(e.NewItems.Cast<T>());
}
// Raise the new event.
protected void RaiseCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (this.CollectionChanged != null)
CollectionChanged(sender, e);
}
// Don't forget to flush the list when your ready with your action or else the last actions will not be 'raised'
public void Flush()
{
if (_lastAction.HasValue && (_itemBuffer.Count > 0))
{
RaiseCollectionChanged(this, new NotifyCollectionChangedEventArgs(_lastAction.Value, _itemBuffer));
_itemBuffer.Clear();
_lastAction = null;
}
}
// new event
public override event NotifyCollectionChangedEventHandler CollectionChanged;
}
玩得开心!J3R03N
这实际上不起作用。当您尝试使用多个项目引发收集已更改事件时,您将得到一个NotSupportedException(不支持Range操作)。建议查看其他解决方案,例如:http://binarysculpting.com/2012/04/03/adding-many-entries-to-an-observable-collection-in-a-performance-friendly-way/或http: //peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/,或http://stackoverflow.com/questions/670577/observablecollection-doesnt-support-addrange-method-soi-i-得到通知的换每个。 – Charlie 2013-11-26 01:31:06
看到这个http://stackoverflow.com/questions/1007691/observablecollection-databinding-performance – Sauron 2009-09-09 09:32:00