204 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
//--------------------------------------------------------------------------
 | 
						|
// 
 | 
						|
//  Copyright (c) Microsoft Corporation.  All rights reserved. 
 | 
						|
// 
 | 
						|
//  File: ObservableConcurrentDictionary.cs
 | 
						|
//
 | 
						|
//--------------------------------------------------------------------------
 | 
						|
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Collections.Specialized;
 | 
						|
using System.ComponentModel;
 | 
						|
using System.Diagnostics;
 | 
						|
using System.Threading;
 | 
						|
 | 
						|
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 bool TryAdd(TKey key, TValue value)
 | 
						|
        {
 | 
						|
            return TryAddWithNotification(key, value);
 | 
						|
        }
 | 
						|
 | 
						|
        public ICollection<TValue> Values {
 | 
						|
            get { return _dictionary.Values; }
 | 
						|
        }
 | 
						|
 | 
						|
        public TValue this[TKey key] {
 | 
						|
            get { return _dictionary[key]; }
 | 
						|
            set { UpdateWithNotification(key, value); }
 | 
						|
        }
 | 
						|
 | 
						|
        public bool TryRemove(TKey key, out TValue value)
 | 
						|
        {
 | 
						|
            return TryRemoveWithNotification(key, out value);
 | 
						|
        }
 | 
						|
        #endregion
 | 
						|
    }
 | 
						|
} |