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; 
     } 

    } 
}