7

我想創建一個ObservableConcurrentDictionary。此對象將用於多線程應用程序,並且它的數據用於通過控件ItemsSource屬性填充控件。如何創建使用ConcurrentDictionary,INotifyCollectionChanged定製觀察的集合,INotifyPropertyChanged的

這是我想出了實施:

public sealed class ObservableConcurrentDictionary<TKey, TValue> : ConcurrentDictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged 
{ 
    #region Constructors 

    public ObservableConcurrentDictionary() 
     : base() 
    { 

    } 

    public ObservableConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) 
     : base(collection) 
    { 

    } 


    public ObservableConcurrentDictionary(IEqualityComparer<TKey> comparer) 
     : base(comparer) 
    { 

    } 


    public ObservableConcurrentDictionary(int concurrencyLevel, int capacity) 
     : base(concurrencyLevel, capacity) 
    { 

    } 


    public ObservableConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) 
     : base(collection, comparer) 
    { 

    } 


    public ObservableConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer<TKey> comparer) 
     : base(concurrencyLevel, capacity, comparer) 
    { 

    } 

    public ObservableConcurrentDictionary(int concurrencyLevel, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) 
     : base(concurrencyLevel, collection, comparer) 
    { 

    } 

    #endregion 

    #region Public Methods 

    public new TValue AddOrUpdate(TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory) 
    { 
     // Stores the value 
     TValue value; 
     // If key exists 
     if (base.ContainsKey(key)) 
     { 
      // Update value and raise event 
      value = base.AddOrUpdate(key, addValueFactory, updateValueFactory); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace)); 
     } 
     // Else if key does not exist 
     else 
     { 
      // Add value and raise event 
      value = base.AddOrUpdate(key, addValueFactory, updateValueFactory); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add)); 
     } 
     // Returns the value 
     return value; 
    } 

    public void Clear() 
    { 
     // Clear dictionary 
     base.Clear(); 
     // Raise event 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
    } 

    public new TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory) 
    { 
     // Stores the value 
     TValue value; 
     // If key exists 
     if (base.ContainsKey(key)) 
      // Get value 
      value = base.GetOrAdd(key, valueFactory); 
     // Else if key does not exist 
     else 
     { 
      // Add value and raise event 
      value = base.GetOrAdd(key, valueFactory); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add)); 
     } 
     // Return value 
     return value; 
    } 

    public new TValue GetOrAdd(TKey key, TValue value) 
    { 
     // If key exists 
     if (base.ContainsKey(key)) 
      // Get value 
      base.GetOrAdd(key, value); 
     // Else if key does not exist 
     else 
     { 
      // Add value and raise event 
      base.GetOrAdd(key, value); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add)); 
     } 
     // Return value 
     return value; 
    } 

    public new bool TryAdd(TKey key, TValue value) 
    { 
     // Stores tryAdd 
     bool tryAdd; 
     // If added 
     if (tryAdd = base.TryAdd(key, value)) 
      // Raise event 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add)); 
     // Return tryAdd 
     return tryAdd; 
    } 

    public new bool TryRemove(TKey key, out TValue value) 
    { 
     // Stores tryRemove 
     bool tryRemove; 
     // If removed 
     if (tryRemove = base.TryRemove(key, out value)) 
      // Raise event 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove)); 
     // Return tryAdd 
     return tryRemove; 
    } 

    public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue) 
    { 
     // Stores tryUpdate 
     bool tryUpdate; 
     // If updated 
     if (tryUpdate = base.TryUpdate(key, newValue, comparisonValue)) 
      // Raise event 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace)); 
     // Return tryUpdate 
     return tryUpdate; 
    } 

    #endregion 

    #region Private Methods 

    private void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     if (CollectionChanged != null) 
      CollectionChanged(this, e); 
    } 

    #endregion 

    #region INotifyCollectionChanged Members 

    public event NotifyCollectionChangedEventHandler CollectionChanged; 

    #endregion 

    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 

    #endregion 
} 

不幸的是,解決方案不會像預期的那樣 - 事實上,它並沒有在所有的工作。關於我在做什麼錯誤或做出更好的解決方案的任何想法存在?

請注意,我不能使用的ObservableCollection,因此,我必須寫我自己的觀察的集合。

編輯: 工作版本如下。希望這可以幫助有類似問題的其他人。

public sealed class ObservableConcurrentDictionary<TKey, TValue> : ConcurrentDictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged 
{ 
    public ObservableConcurrentDictionary() 
     : base() 
    { 

    } 

    public ObservableConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) 
     : base(collection) 
    { 

    } 

    public ObservableConcurrentDictionary(IEqualityComparer<TKey> comparer) 
     : base(comparer) 
    { 

    } 

    public ObservableConcurrentDictionary(int concurrencyLevel, int capacity) 
     : base(concurrencyLevel, capacity) 
    { 

    } 

    public ObservableConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) 
     : base(collection, comparer) 
    { 

    } 

    public ObservableConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer<TKey> comparer) 
     : base(concurrencyLevel, capacity, comparer) 
    { 

    } 

    public ObservableConcurrentDictionary(int concurrencyLevel, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) 
     : base(concurrencyLevel, collection, comparer) 
    { 

    } 

    public new TValue AddOrUpdate(TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory) 
    { 
     // Stores the value 
     TValue value; 
     // If key exists 
     if (base.ContainsKey(key)) 
     { 
      // Update value and raise event 
      value = base.AddOrUpdate(key, addValueFactory, updateValueFactory); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value)); 
     } 
     // Else if key does not exist 
     else 
     { 
      // Add value and raise event 
      value = base.AddOrUpdate(key, addValueFactory, updateValueFactory); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 
     } 
     // Returns the value 
     return value; 
    } 

    public new void Clear() 
    { 
     // Clear dictionary 
     base.Clear(); 
     // Raise event 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
    } 

    public new TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory) 
    { 
     // Stores the value 
     TValue value; 
     // If key exists 
     if (base.ContainsKey(key)) 
      // Get value 
      value = base.GetOrAdd(key, valueFactory); 
     // Else if key does not exist 
     else 
     { 
      // Add value and raise event 
      value = base.GetOrAdd(key, valueFactory); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 
     } 
     // Return value 
     return value; 
    } 

    public new TValue GetOrAdd(TKey key, TValue value) 
    { 
     // If key exists 
     if (base.ContainsKey(key)) 
      // Get value 
      base.GetOrAdd(key, value); 
     // Else if key does not exist 
     else 
     { 
      // Add value and raise event 
      base.GetOrAdd(key, value); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 
     } 
     // Return value 
     return value; 
    } 

    public new bool TryAdd(TKey key, TValue value) 
    { 
     // Stores tryAdd 
     bool tryAdd; 
     // If added 
     if (tryAdd = base.TryAdd(key, value)) 
      // Raise event 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 
     // Return tryAdd 
     return tryAdd; 
    } 

    public new bool TryRemove(TKey key, out TValue value) 
    { 
     // Stores tryRemove 
     bool tryRemove; 
     // If removed 
     if (tryRemove = base.TryRemove(key, out value)) 
      // Raise event 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, value)); 
     // Return tryAdd 
     return tryRemove; 
    } 

    public new bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue) 
    { 
     // Stores tryUpdate 
     bool tryUpdate; 
     // If updated 
     if (tryUpdate = base.TryUpdate(key, newValue, comparisonValue)) 
      // Raise event 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newValue)); 
     // Return tryUpdate 
     return tryUpdate; 
    } 

    private void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     if (CollectionChanged != null) 
      CollectionChanged(this, e); 
    } 

    public event NotifyCollectionChangedEventHandler CollectionChanged; 

    public event PropertyChangedEventHandler PropertyChanged; 
} 
+0

「它根本不起作用」 - 是無效的問題描述。 請告訴我們您收到了哪些錯誤,您使用哪些代碼來測試它以及您無法使用ObservableCollection的原因。 – Euphoric 2010-10-14 11:37:02

回答

2

快速通過你的代碼沒有從你身邊的任何eplanation我只能猜測。 我不認爲在NotifyCollectionChangedEventArgs上設置Action就足夠了。還有NewItems,OldItems屬性,告訴用戶哪些項目發生了變化。

還要注意的是,雖然這些都是收藏品,許多WPF組件支持在通過數據綁定一次只能單個項目的變化。

+0

我對這個模糊的描述表示歉意。昨天是漫長而令人沮喪的一天。你讓我朝着正確的方向前進。萬物現在正常工作。謝謝! – c0D3l0g1c 2010-10-15 02:57:29

11

我無法獲得OPs樣品的工作。無論我嘗試什麼,都會一直提高線程異常的中繼負載。

但是,由於我也是在實現INotifyCollectionChanged和INotifyPropertyChanged的接口需要一個線程安全的集合,我用Google搜索了一圈,發現從微軟自己的傢伙的實現。

下載該文件http://code.msdn.microsoft.com/Samples-for-Parallel-b4b76364和搜索存檔中ObservableConcurrentDictionary.cs。

就像一個魅力!

+1

那個鏈接改變了我的生活。謝謝 :) – Quanta 2013-05-01 15:00:47

1

我開發了一個ObservableConcurrentDictionnary的緊密版本,請評論/建議......

...其中TValue:對象{使用你的類,而不是對象...}

Qurlet

using System; 
using System.Collections.Concurrent; 
using System.Collections.Generic; 
using System.Collections.Specialized; 
using System.ComponentModel; 

namespace Collections 
{ 
    public class ObservableConcurrentDictionary<TValue> : ConcurrentDictionary<Int32, TValue>, INotifyCollectionChanged, INotifyPropertyChanged 
     where TValue : Object , new() 
    { 
     public event NotifyCollectionChangedEventHandler CollectionChanged; 
     protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs changeAction) 
     { 
      var eh = CollectionChanged; 
      if (eh == null) return; 

      eh(this, changeAction); 

      OnPropertyChanged(); 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
     private void OnPropertyChanged() 
     { 
      var eh = PropertyChanged; 
      if (eh == null) return; 

      // All properties : Keys, Values, Count, IsEmpty 
      eh(this, new PropertyChangedEventArgs(null)); 
     } 

     #region Ctors 
     public ObservableConcurrentDictionary() 
      : base() 
     { 

     } 

     public ObservableConcurrentDictionary(IEnumerable<KeyValuePair<Int32, TValue>> collection) 
      : base(collection) 
     { 

     } 

     public ObservableConcurrentDictionary(IEqualityComparer<Int32> comparer) 
      : base(comparer) 
     { 

     } 

     public ObservableConcurrentDictionary(int concurrencyLevel, int capacity) 
      : base(concurrencyLevel, capacity) 
     { 

     } 

     public ObservableConcurrentDictionary(IEnumerable<KeyValuePair<Int32, TValue>> collection, IEqualityComparer<Int32> comparer) 
      : base(collection, comparer) 
     { 

     } 

     public ObservableConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer<Int32> comparer) 
      : base(concurrencyLevel, capacity, comparer) 
     { 

     } 

     public ObservableConcurrentDictionary(int concurrencyLevel, IEnumerable<KeyValuePair<Int32, TValue>> collection, IEqualityComparer<Int32> comparer) 
      : base(concurrencyLevel, collection, comparer) 
     { 

     } 
     #endregion 

     public new void Clear() 
     { 
      // Clear dictionary 
      base.Clear(); 
      // Raise event 
      OnCollectionChanged(changeAction: new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
     } 

     public new TValue AddOrUpdate(Int32 key, Func<Int32, TValue> addValueFactory, 
      Func<Int32, TValue, TValue> updateValueFactory) 
     { 
      bool isUpdated = false; 
      TValue oldValue = default(TValue); 

      TValue value = base.AddOrUpdate(key, addValueFactory, (k, v) => 
      { 
       isUpdated = true; 
       oldValue = v; 
       return updateValueFactory(k, v); 
      }); 

      if (isUpdated) OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, oldValue)); 

      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 
      return value; 
     } 

     public new TValue AddOrUpdate(Int32 key, TValue addValue, Func<Int32, TValue, TValue> updateValueFactory) 
     { 
      bool isUpdated = false; 
      TValue oldValue = default(TValue); 

      TValue value = base.AddOrUpdate(key, addValue, (k, v) => 
      { 
       isUpdated = true; 
       oldValue = v; 
       return updateValueFactory(k, v); 
      }); 

      if (isUpdated) OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, oldValue)); 

      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 
      return value; 
     } 

     public new TValue GetOrAdd(Int32 key, Func<Int32, TValue> addValueFactory) 
     { 
      bool isAdded = false; 

      TValue value = base.GetOrAdd(key, k => 
      { 
       isAdded = true; 
       return addValueFactory(k); 
      }); 

      if (isAdded) OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 

      return value; 
     } 

     public new TValue GetOrAdd(Int32 key, TValue value) 
     { 
      return GetOrAdd(key, k => value); 
     } 

     public new bool TryAdd(Int32 key, TValue value) 
     { 
      bool tryAdd = base.TryAdd(key, value); 

      if (tryAdd) OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 

      return tryAdd; 
     } 

     public new bool TryRemove(Int32 key, out TValue value) 
     { 
      // Stores tryRemove 
      bool tryRemove = base.TryRemove(key, out value); 

      // If removed raise event 
      if (tryRemove) OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, value)); 

      return tryRemove; 
     } 

     public new bool TryUpdate(Int32 key, TValue newValue, TValue comparisonValue) 
     { 
      // Stores tryUpdate 
      bool tryUpdate = base.TryUpdate(key, newValue, comparisonValue); 

      if (tryUpdate) OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newValue, comparisonValue)); 

      return tryUpdate; 
     } 

    } 
}