//--------------------------------------------------------------------------
//
// 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
{
///
/// Provides a thread-safe dictionary for use with data binding.
///
/// Specifies the type of the keys in this collection.
/// Specifies the type of the values in this collection.
[DebuggerDisplay("Count={Count}")]
public class ObservableConcurrentDictionary :
ICollection>, IDictionary,
INotifyCollectionChanged, INotifyPropertyChanged
{
private readonly SynchronizationContext _context;
private readonly ConcurrentDictionary _dictionary;
///
/// Initializes an instance of the ObservableConcurrentDictionary class.
///
public ObservableConcurrentDictionary()
{
_context = AsyncOperationManager.SynchronizationContext;
_dictionary = new ConcurrentDictionary();
}
/// Event raised when the collection changes.
public event NotifyCollectionChangedEventHandler CollectionChanged;
/// Event raised when a property on the collection changes.
public event PropertyChangedEventHandler PropertyChanged;
///
/// Notifies observers of CollectionChanged or PropertyChanged of an update to the dictionary.
///
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);
}
}
/// Attempts to add an item to the dictionary, notifying observers of any changes.
/// The item to be added.
/// Whether the add was successful.
private bool TryAddWithNotification(KeyValuePair item)
{
return TryAddWithNotification(item.Key, item.Value);
}
/// Attempts to add an item to the dictionary, notifying observers of any changes.
/// The key of the item to be added.
/// The value of the item to be added.
/// Whether the add was successful.
private bool TryAddWithNotification(TKey key, TValue value)
{
bool result = _dictionary.TryAdd(key, value);
if (result) NotifyObserversOfChange();
return result;
}
/// Attempts to remove an item from the dictionary, notifying observers of any changes.
/// The key of the item to be removed.
/// The value of the item removed.
/// Whether the removal was successful.
private bool TryRemoveWithNotification(TKey key, out TValue value)
{
bool result = _dictionary.TryRemove(key, out value);
if (result) NotifyObserversOfChange();
return result;
}
/// Attempts to add or update an item in the dictionary, notifying observers of any changes.
/// The key of the item to be updated.
/// The new value to set for the item.
/// Whether the update was successful.
private void UpdateWithNotification(TKey key, TValue value)
{
_dictionary[key] = value;
NotifyObserversOfChange();
}
#region ICollection> Members
void ICollection>.Add(KeyValuePair item)
{
TryAddWithNotification(item);
}
void ICollection>.Clear()
{
((ICollection>)_dictionary).Clear();
NotifyObserversOfChange();
}
bool ICollection>.Contains(KeyValuePair item)
{
return ((ICollection>)_dictionary).Contains(item);
}
void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex)
{
((ICollection>)_dictionary).CopyTo(array, arrayIndex);
}
int ICollection>.Count
{
get { return ((ICollection>)_dictionary).Count; }
}
bool ICollection>.IsReadOnly
{
get { return ((ICollection>)_dictionary).IsReadOnly; }
}
bool ICollection>.Remove(KeyValuePair item)
{
TValue temp;
return TryRemoveWithNotification(item.Key, out temp);
}
#endregion
#region IEnumerable> Members
IEnumerator> IEnumerable>.GetEnumerator()
{
return ((ICollection>)_dictionary).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((ICollection>)_dictionary).GetEnumerator();
}
#endregion
#region IDictionary Members
public void Add(TKey key, TValue value)
{
TryAddWithNotification(key, value);
}
public bool ContainsKey(TKey key)
{
return _dictionary.ContainsKey(key);
}
public ICollection 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 Values
{
get { return _dictionary.Values; }
}
public TValue this[TKey key]
{
get { return _dictionary[key]; }
set { UpdateWithNotification(key, value); }
}
#endregion
}
}