如何使用ConcurrentDictionary,INotifyCollectionChanged,INotifyPropertyChanged创建自定义可观察集合

c0D*_*g1c 8 .net wpf inotifycollectionchanged inotifypropertychanged interface-implementation

我正在尝试创建一个ObservableConcurrentDictionary.此对象将用于多线程应用程序,它的数据用于通过控件ItemsSource属性填充控件.

这是我提出的实现:

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
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,解决方案不能按预期工作 - 事实上,它根本不起作用.关于我做错了什么或做出更好的解决方案的任何想法都存在?

请注意我不能使用ObservableCollection,因此我必须编写自己的Observable集合.

编辑:工作版本如下.希望这可以帮助其他有类似问题的人.

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;
}
Run Code Online (Sandbox Code Playgroud)

lig*_*txx 11

我无法让OPs样本起作用.无论我怎样尝试,都会一直提高交叉线程异常的主干负载.

但是,由于我还需要一个实现INotifyCollectionChanged和INotifyPropertyChanged接口的线程安全集合,我用Google搜索并发现了微软自己的实现.

下载此文件http://code.msdn.microsoft.com/Samples-for-Parallel-b4b76364并在存档中搜索ObservableConcurrentDictionary.cs.

奇迹般有效!


Eup*_*ric 2

我只能猜测,快速浏览您的代码,而无需您的任何解释。我认为在 NotifyCollectionChangedEventArgs 上设置 Action 就足够了。还有NewItems,OldItems属性,告诉订阅者哪些项目发生了变化。

另请注意,虽然这些是集合,但许多 WPF 组件仅支持通过 DataBinding 一次更改单个项目。