增加WPF的ObservableCollection性能

增加WPF的ObservableCollection性能

问题描述:

目前我有两个WPF列表框模仿了以下功能增加WPF的ObservableCollection性能

Word 2007 customize screen http://tlt.its.psu.edu/suggestions/international/graphics/vista/WordCustomize.gif

我使用2个ObservableCollections,让用户选择他们需要的任何物品(灵活性是关键在这里)。主要问题是我有成千上万项目被分组在两个列表框中。总的来说,所有的设计作品都很好(有几十个项目),但是我的绊脚石是当屏幕冻结时(用于在不同线程上运行的时间),用户从左到右复制所有可用项目时。

看着ObservableCollection它缺少一个AddRange方法,并且在互联网上有各种实现可用。我也知道,CollectionChanged事件被不必要地解雇,因为每个项目都被复制到可怕的性能上。

这很可能是因为我不得不允许用户从将来超过10000个项目组中选择,这听起来像一个糟糕的主意,但由于列表框(CollectionViewSource)上的分组非常有效但有副作用切换虚拟化的两个列表框

当数据绑定到ObservableCollection时加载带有数千项目的列表框时,我该怎么做才能提高性能?有没有可以推荐的AddRange类型实现?是我在这里唯一的选择在后台线程上运行这个看起来很昂贵的因为我不从数据库加载数据?

+0

看到这个http://stackoverflow.com/questions/1007691/observablecollection-databinding-performance – Sauron 2009-09-09 09:32:00

我已经删除了CollectionViewSource和分组,并且这些项目以1/2秒的速度被复制,但由于虚拟化不适用于分组,因此分组可能需要一分钟。

我需要决定是否使用CollectionViewSource

+0

collectionviewsource在初始绑定发生时有效地工作,但在运行时效率非常低下。 我现在在使用LINQ的代码中进行排序/筛选 – Vault 2009-09-28 09:54:13

+0

这是怎么回答的? – 2016-11-14 18:21:56

您可能会继承ObservableCollection<T>(或直接执行INotifyCollectionChanged)以添加BeginUpdateEndUpdate方法。在调用BeginUpdateEndUpdate之间进行的更改将排队,然后合并为一个(或若有单独范围存在若干个)NotifyCollectionChangedEventArgs对象,调用EndUpdate时将传递到CollectionChanged事件的处理程序。

+1

据我所知,WPF控件不支持集合的范围更新,并且当他们在一个CollectionChanged事件中收到多个项目时引发异常。 – 2009-11-26 23:34:27

+1

WTF?!为什么提供能够在事件参数中指定多个项目(如果它们不支持它)?我已经实现了我的答案中描述的集合,但没有时间实际测试它......我刚刚做了,而且看起来你是对的:(所以我的集合不能用于绑定场景.. 。 – 2009-11-26 23:58:26

+0

不能在WPF 4.0中工作:( – 2009-11-27 00:03:19

你可以找到一个线程安全可观察集合here。使您的Observable集合线程安全并将其绑定到列表框。

+0

这就是我使用的方法,它工作得很好 你可以使用BackgroundWorker来填充你的ObservableCollection,并看到你的ListBox正在被动态填充 – japf 2009-09-09 10:10:49

+0

这种方法仍然是在UI线程上抛出不合理数量的事件,因为每个添加的项目都会抛出自己的收集更改事件,但这不会解决问题 – 2013-01-18 19:35:27

+0

链接已死 – JobaDiniz 2016-08-01 22:10:14

我无法抗拒回答这个。我认为你不会再需要这个答案,但也许有人可以使用它。不要想太多(不要使用这个多线程(这会使事情容易出错并且不必要的复杂,只能使用线程进行硬计算/ 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

+0

这实际上不起作用。当您尝试使用多个项目引发收集已更改事件时,您将得到一个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