2009-09-09 97 views
7

目前我有兩個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

回答

2

我已經刪除了CollectionViewSource和分組,並且這些項目以1/2秒的速度被複制,但由於虛擬化不適用於分組,因此分組可能需要一分鐘。

我需要決定是否使用CollectionViewSource

+0

collectionviewsource在初始綁定發生時有效地工作,但在運行時效率非常低下。 我現在在使用LINQ的代碼中進行排序/篩選 – Vault 2009-09-28 09:54:13

+0

這是怎麼回答的? – 2016-11-14 18:21:56

1

您可能會繼承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

1

你可以找到一個線程安全可觀察集合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

2

我無法抗拒回答這個。我認爲你不會再需要這個答案,但也許有人可以使用它。不要想太多(不要使用這個多線程(這會使事情容易出錯並且不必要的複雜,只能使用線程進行硬計算/ 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