いまでも時々いいねやストックを頂きますが、こちらのライブラリを利用したほうが各確実です。
XAML系テクノロジを使っていると時々欲しくなる ObservableDictionery<> について考えてみました。
まずは非ジェネリックの DictionaryBase に相当するクラスをつくります。
KeyedCollection というクラスが用意されているのでこれをベースにします。
これは Dictionary に近い挙動をする Collection の派生クラスです。(内部に Dictionary を持っています。)
これに IDictionary<> を実装させます。
CollectionBasedDictionary.cs
public class CollectionBasedDictionary<TKey, TValue>
: KeyedCollection<TKey, KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue> // 必要なら IDictionary も
{
/*
* Dictionary を参考に コンストラクタを記述
*/
protected override TKey GetKeyForItem(KeyValuePair<TKey, TValue> item)
{
return item.Key;
}
/*
* IDictionery<TKey, TValue> のメンバー を記述
* IDictionery<TKey, TValue>.Values の実装がちょっとめんどくさいです…
*/
}
あとは、CollectionBasedDictionary に 対して Collection -> ObsservableCollection と同じ拡張をすればOKです。
ObservableDictionery.cs
public class ObservableDictionary<TKey, TValue>
: CollectionBasedDictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged
{
/*
* Dictionary を参考に コンストラクタを記述
*/
public virtual event NotifyCollectionChangedEventHandler CollectionChanged;
protected virtual event PropertyChangedEventHandler PropertyChanged;
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
{
add
{
PropertyChanged += value;
}
remove
{
PropertyChanged -= value;
}
}
protected const string IndexerName = "Item[]";
protected const string CountName = "Count";
protected override void InsertItem(int index, KeyValuePair<TKey, TValue> item)
{
base.InsertItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newItem, index));
OnPropertyChanged(IndexerName);
OnPropertyChanged(CountName);
}
protected override void RemoveItem(int index)
{
var item = this[index];
base.RemoveItem(index);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, oldItem, index));
OnPropertyChanged(IndexerName);
OnPropertyChanged(CountName);
}
protected override void SetItem(int index, KeyValuePair<TKey, TValue> item)
{
var oldItem = this[index];
base.SetItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newItem, oldItem, index));
OnPropertyChanged(IndexerName);
}
protected override void ClearItems()
{
base.ClearItems();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
OnPropertyChanged(IndexerName);
OnPropertyChanged(CountName);
}
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (CollectionChanged != null)
{
CollectionChanged(this, e);
}
}
protected virtual void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
この方法だと ObservableDictionery が IList<> を実装しているので、 Livet の DispatcherCollection 等にも使用できます。