123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- using System.Collections;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Collections.Specialized;
- using System.ComponentModel;
- using System.Threading;
- namespace InABox.Core
- {
- public class ObservableDictionary<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 ObservableDictionary()
- {
- _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)
- {
- var 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)
- {
- var 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 => ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Count;
- bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => ((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 => _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 => _dictionary.Values;
- public TValue this[TKey key]
- {
- get => _dictionary[key];
- set => UpdateWithNotification(key, value);
- }
- #endregion
- }
- }
|