.NET Framework 4仍没有提供ObservableDictionary类型,如果不实现字典的特性,完全可以用一个简单的包含Key和Value属性的类的ObservableCollection实现。
一个ObservableDictionary应该实现这些接口(参考:《Can I bind my ItemsControl to a dictionary?》):
IDictionary<TKey TValue> ICollection<KeyValuePair<TKey TValue>> IEnumerable<KeyValuePair<TKey TValue>> IDictionary ICollection IEnumerable ISerializable IDeserializationCallback INotifyCollectionChanged INotifyPropertyChanged
看来需要实现的成员会很多,我没有使用封装的办法,而是直接继承了Dictionary<TKey, TValue>,代码:
// ---------------------------------------- // ObservableDictionary.cs // ---------------------------------------- using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Runtime.Serialization; /// <summary> /// ObservableDictionary的实现(oyi319) /// </summary> /// <typeparam name="TKey"></typeparam> /// <typeparam name="TValue"></typeparam> public class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IDictionary<TKey, TValue>, IDictionary, INotifyCollectionChanged, INotifyPropertyChanged { #region 构造 public ObservableDictionary() { } public ObservableDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary) { } public ObservableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : base(dictionary, comparer) { } public ObservableDictionary(IEqualityComparer<TKey> comparer) : base(comparer) { } public ObservableDictionary(int capacity) : base(capacity) { } public ObservableDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer) { } public ObservableDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { } #endregion #region 方法 private void OnCollectionChanged(NotifyCollectionChangedEventArgs args) { if (this.CollectionChanged != null) { this.CollectionChanged(this, args); } } private void OnPropertyChanged(string propertyName) { if (this.PropertyChanged != null) { this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } #endregion #region 重载 void IDictionary.Clear() { if (base.Count > 0) { base.Clear(); this.OnPropertyChanged("Keys"); this.OnPropertyChanged("Values"); this.OnPropertyChanged("Count"); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } } public void Remove(object key) { var k = (TKey)key; if (!base.ContainsKey(k)) { return; //不包含的 } var v = base[k]; var item = new KeyValuePair<TKey, TValue>(k, v); base.Remove(k); this.OnPropertyChanged("Keys"); this.OnPropertyChanged("Values"); this.OnPropertyChanged("Count"); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item)); } object IDictionary.this[object key] { get { return base[(TKey)key]; } set { var k = (TKey)key; if (base.ContainsKey(k)) { var v = base[k]; if (v.Equals((TValue)value)) { return; } var newitem = new KeyValuePair<TKey, TValue>(k, (TValue)value); var oldItem = new KeyValuePair<TKey, TValue>(k, base[k]); base[k] = newitem.Value; this.OnPropertyChanged("Values"); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Replace, newitem, oldItem)); return; } var item = new KeyValuePair<TKey, TValue>(k, (TValue)value); base.Add(k, item.Value); this.OnPropertyChanged("Keys"); this.OnPropertyChanged("Values"); this.OnPropertyChanged("Count"); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); } } public void Add(KeyValuePair<TKey, TValue> item) { base.Add(item.Key, item.Value); this.OnPropertyChanged("Keys"); this.OnPropertyChanged("Values"); this.OnPropertyChanged("Count"); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); } public void Add(object key, object value) { var item = new KeyValuePair<TKey, TValue>((TKey)key, (TValue)value); base.Add(item.Key, item.Value); this.OnPropertyChanged("Keys"); this.OnPropertyChanged("Values"); this.OnPropertyChanged("Count"); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); } void ICollection<KeyValuePair<TKey, TValue>>.Clear() { ((IDictionary)this).Clear(); } public bool Remove(KeyValuePair<TKey, TValue> item) { if (!base.ContainsKey(item.Key)) { return false; } var r = base.Remove(item.Key); this.OnPropertyChanged("Keys"); this.OnPropertyChanged("Values"); this.OnPropertyChanged("Count"); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item)); return r; } public new void Add(TKey key, TValue value) { var item = new KeyValuePair<TKey, TValue>(key, value); base.Add(item.Key, item.Value); this.OnPropertyChanged("Keys"); this.OnPropertyChanged("Values"); this.OnPropertyChanged("Count"); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); } public new bool Remove(TKey key) { if (base.ContainsKey(key)) return false; var v = base[key]; var item = new KeyValuePair<TKey, TValue>(key, v); var r = base.Remove(key); this.OnPropertyChanged("Keys"); this.OnPropertyChanged("Values"); this.OnPropertyChanged("Count"); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item)); return r; } TValue IDictionary<TKey, TValue>.this[TKey key] { get { return base[key]; } set { if(base.ContainsKey(key)) { var v = base[key]; if(v.Equals(value)) { return; } var newitem = new KeyValuePair<TKey, TValue>(key, value); var oldItem = new KeyValuePair<TKey, TValue>(key, base[key]); base[key] = newitem.Value; this.OnPropertyChanged("Values"); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Replace, newitem, oldItem)); return; } var item = new KeyValuePair<TKey, TValue>(key, value); base.Add(key, item.Value); this.OnPropertyChanged("Keys"); this.OnPropertyChanged("Values"); this.OnPropertyChanged("Count"); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); } } public event NotifyCollectionChangedEventHandler CollectionChanged; public event PropertyChangedEventHandler PropertyChanged; #endregion }
注:代码有待完善,请谨慎使用。