using System; using System.Linq; using System.ComponentModel; using System.Collections.Generic; using System.Collections; #if NETFX_CORE using specialized = System.Collections.Specialized; #else using specialized = PlatformSupport.Collections.Specialized; #endif namespace PlatformSupport.Collections.ObjectModel { public class ObservableDictionary : IDictionary, specialized.INotifyCollectionChanged, INotifyPropertyChanged { private const string CountString = "Count"; private const string IndexerName = "Item[]"; private const string KeysName = "Keys"; private const string ValuesName = "Values"; private IDictionary _Dictionary; protected IDictionary Dictionary { get { return _Dictionary; } } #region Constructors public ObservableDictionary() { _Dictionary = new Dictionary(); } public ObservableDictionary(IDictionary dictionary) { _Dictionary = new Dictionary(dictionary); } public ObservableDictionary(IEqualityComparer comparer) { _Dictionary = new Dictionary(comparer); } public ObservableDictionary(int capacity) { _Dictionary = new Dictionary(capacity); } public ObservableDictionary(IDictionary dictionary, IEqualityComparer comparer) { _Dictionary = new Dictionary(dictionary, comparer); } public ObservableDictionary(int capacity, IEqualityComparer comparer) { _Dictionary = new Dictionary(capacity, comparer); } #endregion #region IDictionary Members public void Add(TKey key, TValue value) { Insert(key, value, true); } public bool ContainsKey(TKey key) { return Dictionary.ContainsKey(key); } public ICollection Keys { get { return Dictionary.Keys; } } public bool Remove(TKey key) { if (key == null) throw new ArgumentNullException("key"); TValue value; Dictionary.TryGetValue(key, out value); var removed = Dictionary.Remove(key); if (removed) //OnCollectionChanged(NotifyCollectionChangedAction.Remove, new KeyValuePair(key, value)); OnCollectionChanged(); return removed; } 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 { Insert(key, value, false); } } #endregion #region ICollection> Members public void Add(KeyValuePair item) { Insert(item.Key, item.Value, true); } public void Clear() { if (Dictionary.Count > 0) { Dictionary.Clear(); OnCollectionChanged(); } } public bool Contains(KeyValuePair item) { return Dictionary.Contains(item); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { Dictionary.CopyTo(array, arrayIndex); } public int Count { get { return Dictionary.Count; } } public bool IsReadOnly { get { return Dictionary.IsReadOnly; } } public bool Remove(KeyValuePair item) { return Remove(item.Key); } #endregion #region IEnumerable> Members public IEnumerator> GetEnumerator() { return Dictionary.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)Dictionary).GetEnumerator(); } #endregion #region INotifyCollectionChanged Members public event specialized.NotifyCollectionChangedEventHandler CollectionChanged; #endregion #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion public void AddRange(IDictionary items) { if (items == null) throw new ArgumentNullException("items"); if (items.Count > 0) { if (Dictionary.Count > 0) { if (items.Keys.Any((k) => Dictionary.ContainsKey(k))) throw new ArgumentException("An item with the same key has already been added."); else foreach (var item in items) Dictionary.Add(item); } else _Dictionary = new Dictionary(items); OnCollectionChanged(specialized.NotifyCollectionChangedAction.Add, items.ToArray()); } } private void Insert(TKey key, TValue value, bool add) { if (key == null) throw new ArgumentNullException("key"); TValue item; if (Dictionary.TryGetValue(key, out item)) { if (add) throw new ArgumentException("An item with the same key has already been added."); if (Equals(item, value)) return; Dictionary[key] = value; OnCollectionChanged(specialized.NotifyCollectionChangedAction.Replace, new KeyValuePair(key, value), new KeyValuePair(key, item)); } else { Dictionary[key] = value; OnCollectionChanged(specialized.NotifyCollectionChangedAction.Add, new KeyValuePair(key, value)); } } private void OnPropertyChanged() { OnPropertyChanged(CountString); OnPropertyChanged(IndexerName); OnPropertyChanged(KeysName); OnPropertyChanged(ValuesName); } protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } private void OnCollectionChanged() { OnPropertyChanged(); if (CollectionChanged != null) CollectionChanged(this, new specialized.NotifyCollectionChangedEventArgs(specialized.NotifyCollectionChangedAction.Reset)); } private void OnCollectionChanged(specialized.NotifyCollectionChangedAction action, KeyValuePair changedItem) { OnPropertyChanged(); if (CollectionChanged != null) CollectionChanged(this, new specialized.NotifyCollectionChangedEventArgs(action, changedItem)); } private void OnCollectionChanged(specialized.NotifyCollectionChangedAction action, KeyValuePair newItem, KeyValuePair oldItem) { OnPropertyChanged(); if (CollectionChanged != null) CollectionChanged(this, new specialized.NotifyCollectionChangedEventArgs(action, newItem, oldItem)); } private void OnCollectionChanged(specialized.NotifyCollectionChangedAction action, IList newItems) { OnPropertyChanged(); if (CollectionChanged != null) CollectionChanged(this, new specialized.NotifyCollectionChangedEventArgs(action, newItems)); } } }