Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET ObservableDictionary

I have written the following class which implements(or tries to!) a dictionary with notifications:

public partial class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, INotifyCollectionChanged {     public ObservableDictionary() : base() { }     public ObservableDictionary(int capacity) : base(capacity) { }     public ObservableDictionary(IEqualityComparer<TKey> comparer) : base(comparer) { }     public ObservableDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary) { }     public ObservableDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer) { }     public ObservableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : base(dictionary, comparer) { }      public event NotifyCollectionChangedEventHandler CollectionChanged;      public new TValue this[TKey key]     {         get         {             return base[key];         }         set         {             OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, key, 0));             base[key] = value;         }     }      public new void Add(TKey key, TValue value)     {         base.Add(key, value);         OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, key, 0));     }      public new bool Remove(TKey key)     {         bool x = base.Remove(key);         OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, key, 0));         return x;     }      public new void Clear()     {         base.Clear();         OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));     }       protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)     {         if (CollectionChanged != null)         {             CollectionChanged(this, e);         }     } } 

In another class, I have a listener for the MyObservableDictionary.CollectionChanged event:

The problem I'm having is that the event doesn't fire. How can I fix this?

like image 285
Cos Avatar asked Apr 14 '11 12:04

Cos


2 Answers

The Microsoft ParallelExtensionsExtras provides this class which is not only observable but is also concurrent:

Now available via Nuget: https://www.nuget.org/packages/MSFT.ParallelExtensionsExtras/

The source code was recently updated for .NET Standard 2.1 on 05/11/2020 and the source code is available at GitHub: https://github.com/dotnet/samples/tree/master/csharp/parallel/ParallelExtensionsExtras

Note that some of the features are now a part of newer .NET frameworks. Are the ParallelExtensions "Extras" still of value?

Microsoft Tour Blog: https://blogs.msdn.microsoft.com/pfxteam/2010/04/04/a-tour-of-parallelextensionsextras/

//-------------------------------------------------------------------------- //  //  Copyright (c) Microsoft Corporation.  All rights reserved.  //  //  File: ObservableConcurrentDictionary.cs // //--------------------------------------------------------------------------  using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Threading; using System.Diagnostics;  namespace System.Collections.Concurrent {     /// <summary>     /// Provides a thread-safe dictionary for use with data binding.     /// </summary>     /// <typeparam name="TKey">Specifies the type of the keys in this collection.</typeparam>     /// <typeparam name="TValue">Specifies the type of the values in this collection.</typeparam>     [DebuggerDisplay("Count={Count}")]     public class ObservableConcurrentDictionary<TKey, TValue> :         ICollection<KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue>,         INotifyCollectionChanged, INotifyPropertyChanged     {         private readonly SynchronizationContext _context;         private readonly ConcurrentDictionary<TKey, TValue> _dictionary;          /// <summary>         /// Initializes an instance of the ObservableConcurrentDictionary class.         /// </summary>         public ObservableConcurrentDictionary()         {             _context = AsyncOperationManager.SynchronizationContext;             _dictionary = new ConcurrentDictionary<TKey, TValue>();         }          /// <summary>Event raised when the collection changes.</summary>         public event NotifyCollectionChangedEventHandler CollectionChanged;         /// <summary>Event raised when a property on the collection changes.</summary>         public event PropertyChangedEventHandler PropertyChanged;          /// <summary>         /// Notifies observers of CollectionChanged or PropertyChanged of an update to the dictionary.         /// </summary>         private void NotifyObserversOfChange()         {             var collectionHandler = CollectionChanged;             var propertyHandler = PropertyChanged;             if (collectionHandler != null || propertyHandler != null)             {                 _context.Post(s =>                 {                     if (collectionHandler != null)                     {                         collectionHandler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));                     }                     if (propertyHandler != null)                     {                         propertyHandler(this, new PropertyChangedEventArgs("Count"));                         propertyHandler(this, new PropertyChangedEventArgs("Keys"));                         propertyHandler(this, new PropertyChangedEventArgs("Values"));                     }                 }, null);             }         }          /// <summary>Attempts to add an item to the dictionary, notifying observers of any changes.</summary>         /// <param name="item">The item to be added.</param>         /// <returns>Whether the add was successful.</returns>         private bool TryAddWithNotification(KeyValuePair<TKey, TValue> item)         {             return TryAddWithNotification(item.Key, item.Value);         }          /// <summary>Attempts to add an item to the dictionary, notifying observers of any changes.</summary>         /// <param name="key">The key of the item to be added.</param>         /// <param name="value">The value of the item to be added.</param>         /// <returns>Whether the add was successful.</returns>         private bool TryAddWithNotification(TKey key, TValue value)         {             bool result = _dictionary.TryAdd(key, value);             if (result) NotifyObserversOfChange();             return result;         }          /// <summary>Attempts to remove an item from the dictionary, notifying observers of any changes.</summary>         /// <param name="key">The key of the item to be removed.</param>         /// <param name="value">The value of the item removed.</param>         /// <returns>Whether the removal was successful.</returns>         private bool TryRemoveWithNotification(TKey key, out TValue value)         {             bool result = _dictionary.TryRemove(key, out value);             if (result) NotifyObserversOfChange();             return result;         }          /// <summary>Attempts to add or update an item in the dictionary, notifying observers of any changes.</summary>         /// <param name="key">The key of the item to be updated.</param>         /// <param name="value">The new value to set for the item.</param>         /// <returns>Whether the update was successful.</returns>         private void UpdateWithNotification(TKey key, TValue value)         {             _dictionary[key] = value;             NotifyObserversOfChange();         }          #region ICollection<KeyValuePair<TKey,TValue>> Members         void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)         {             TryAddWithNotification(item);         }          void ICollection<KeyValuePair<TKey, TValue>>.Clear()         {             ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Clear();             NotifyObserversOfChange();         }          bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)         {             return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Contains(item);         }          void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)         {             ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).CopyTo(array, arrayIndex);         }          int ICollection<KeyValuePair<TKey, TValue>>.Count         {             get { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Count; }         }          bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly         {             get { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).IsReadOnly; }         }          bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)         {             TValue temp;             return TryRemoveWithNotification(item.Key, out temp);         }         #endregion          #region IEnumerable<KeyValuePair<TKey,TValue>> Members         IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()         {             return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).GetEnumerator();         }          IEnumerator IEnumerable.GetEnumerator()         {             return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).GetEnumerator();         }         #endregion          #region IDictionary<TKey,TValue> Members         public void Add(TKey key, TValue value)         {             TryAddWithNotification(key, value);         }          public bool ContainsKey(TKey key)         {             return _dictionary.ContainsKey(key);         }          public ICollection<TKey> Keys         {             get { return _dictionary.Keys; }         }          public bool Remove(TKey key)         {             TValue temp;             return TryRemoveWithNotification(key, out temp);         }          public bool TryGetValue(TKey key, out TValue value)         {             return _dictionary.TryGetValue(key, out value);         }          public ICollection<TValue> Values         {             get { return _dictionary.Values; }         }          public TValue this[TKey key]         {             get { return _dictionary[key]; }             set { UpdateWithNotification(key, value); }         }         #endregion     } } 
like image 133
VoteCoffee Avatar answered Oct 16 '22 23:10

VoteCoffee


I'd suggest that you implement the IDictionary<TKey, TValue> instead of inheriting from Dictionary<TKey, TValue>. Since you have to use new rather than override it's possible that the methods are simply being called on the base class rather than your class. I'd be tempted to use a Dictionary<TKey, TValue> internally to do the actual storing of data.

In fact I found this: http://blogs.microsoft.co.il/blogs/shimmy/archive/2010/12/26/observabledictionary-lt-tkey-tvalue-gt-c.aspx

like image 44
ilivewithian Avatar answered Oct 16 '22 22:10

ilivewithian