.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
}
注:代码有待完善,请谨慎使用。