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