现在的位置: 首页 > 综合 > 正文

实现一个ObservableDictionary

2014年03月26日 ⁄ 综合 ⁄ 共 5741字 ⁄ 字号 评论关闭

.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
}

注:代码有待完善,请谨慎使用。

抱歉!评论已关闭.