LoginSignup
21
17

More than 1 year has passed since last update.

ObservableDictionery をつくる

Last updated at Posted at 2013-10-12

いまでも時々いいねやストックを頂きますが、こちらのライブラリを利用したほうが各確実です。

Cysharp/ObservableCollections

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 等にも使用できます。

21
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
17