2009-07-08 22 views
25

C#でWPF DataBindingのObservable Dictionary Classを作成しようとしています。 私はここアンディからの素敵な例を見つけました。それによるとTwo Way Data Binding With a Dictionary in WPFDataBinding/WPFの一般的なObservable DictionaryクラスC#

、私は次のようにコードを変更しようとしました:

class ObservableDictionary : ViewModelBase 
{ 
    public ObservableDictionary(Dictionary<TKey, TValue> dictionary) 
    { 
     _data = dictionary; 
    } 

    private Dictionary<TKey, TValue> _data; 

    public Dictionary<TKey, TValue> Data 
    { 
     get { return this._data; } 
    } 

    private KeyValuePair<TKey, TValue>? _selectedKey = null; 
    public KeyValuePair<TKey, TValue>? SelectedKey 
    { 
     get { return _selectedKey; } 
     set 
     { 
      _selectedKey = value; 
      RaisePropertyChanged("SelectedKey"); 
      RaisePropertyChanged("SelectedValue"); 
     } 
    } 

    public TValue SelectedValue 
    { 
     get 
     { 
      return _data[SelectedKey.Value.Key]; 
     } 
     set 
     { 
      _data[SelectedKey.Value.Key] = value; 
      RaisePropertyChanged("SelectedValue"); 
     } 
    } 
} 

}

を残念ながら私はまだ合格する方法がわかりません"一般的な"辞書オブジェクト..任意のアイデア?

ありがとうございました!

乾杯

+0

あなたがやろうとしているものに関して、もう少し詳細を与えることができますか?あなたは "一般的な辞書を渡す"と言うときに書くことができるようにしたいコードの例を表示できますか? – JMarsch

+0

私は異なる辞書を持っています。郵便番号と市。 私は何をしようとしています: - データ(モデル/辞書)をWPF ItemsControlにバインドします。郵便番号の都市を変更すると、モデルが自動的に更新されます。残念ながら、私はINotifyPropertyChangedが必要なので、 "普通の"ディクショナリでOneWay-Bindingしか使用できません。 - INotifyPropertyChangedを実装し、辞書を含むObservableDictionaryを作成します。 –

+0

解決策はあります:http://stackoverflow.com/questions/5663395/net-observabledictionary –

答えて

35

あなたが本当にObservableDictionaryを作りたい場合は、私がIDictionaryINotifyCollectionChangedの両方を実装するクラスを作成することをお勧めしたいです。 Dictionaryを内部的に使用してIDictionaryのメソッドを実装することができます。そのため、自分自身で再実装する必要はありません。

Dictionaryの内部情報が完全にわかっているので、その知識を使ってINotifyCollectionChangedを実装することができます。

+2

コードで詳しく説明できますか?あなたは(私のような)多くのnoobsを助けてくれるでしょう。 chrs – BKSpurgeon

+2

@BKSpurgeon既に利用可能なサンプルがあります:http://blogs.microsoft.co.il/shimmy/2010/12/26/observabledictionarylttkey-tvaluegt-c/(via http://stackoverflow.com/questions/5663395)/net-observabledictionary、質問のコメントにリンクされています)。 – Andy

0

あなたは他の人の辞書になるようなものを書くことはできません。IDictionaryはもちろん、何らかの反射を使わずに観察することはできません。問題は、ディクショナリが追加と削除を呼び出さず、結果としてイベントをバイパスしない追加のミューテータ(Sort、Filterなど)を持つサブクラスである可能性があることです。

私はこのようなことをすることを可能にするコード生成フレームワークが存在すると信じていますが、私はそれに精通していません。

19
+0

私はINotifyCollectionChangedを実装できないようです。それは組立が欠けていると言う。私はあなたのポスト(C#)の上部にすべてのアセンブリをインポートし、私は.NET 3.5がありますが、それを見つけることができません。何か案は? – Joshua

+0

名前空間をインポートしましたが、重大なアセンブリへの参照がない可能性があります。プロジェクトでアセンブリSystem.dllが参照されていることを確認します。 example [here](http://i.stack.imgur.com/4kLAB.png)を参照してください。 – Shimmy

6

歴史的な目的のために、人々を「現在の」経路に置く...それは私ですMicrosoftがVisual Studio 2012のWindows Storeの「基本ページ」テンプレートでこの要件を解決したことを知るためには重要です.LayeredAwarePageをサポートするために、これらは非公開のObservableDictionaryクラスを生成します。

しかし、IDictionaryではなく新しいIObservableMapインターフェイスを直接実装しています。このインターフェイスは、Windows.Foundation.Collections名前空間で定義されたMapChangedイベントとMapChangedEventHandlerを追加します。

以下のスニペットは、プロジェクトの「共通」フォルダに生成LayoutAwarePage.csからわずかObservableDictionaryクラスです:新しいWindows.Foundation.Collections名前空間の

/// <summary> 
    /// Implementation of IObservableMap that supports reentrancy for use as a default view 
    /// model. 
    /// </summary> 
    private class ObservableDictionary<K, V> : IObservableMap<K, V> 
    { 
     private class ObservableDictionaryChangedEventArgs : IMapChangedEventArgs<K> 
     { 
      public ObservableDictionaryChangedEventArgs(CollectionChange change, K key) 
      { 
       CollectionChange = change; 
       Key = key; 
      } 

      public CollectionChange CollectionChange { get; private set; } 
      public K Key { get; private set; } 
     } 

     private Dictionary<K, V> _dictionary = new Dictionary<K, V>(); 
     public event MapChangedEventHandler<K, V> MapChanged; 

     private void InvokeMapChanged(CollectionChange change, K key) 
     { 
      var eventHandler = MapChanged; 
      if (eventHandler != null) 
      { 
       eventHandler(this, new ObservableDictionaryChangedEventArgs(change, key)); 
      } 
     } 

     public void Add(K key, V value) 
     { 
      _dictionary.Add(key, value); 
      InvokeMapChanged(CollectionChange.ItemInserted, key); 
     } 

     public void Add(KeyValuePair<K, V> item) 
     { 
      Add(item.Key, item.Value); 
     } 

     public bool Remove(K key) 
     { 
      if (_dictionary.Remove(key)) 
      { 
       InvokeMapChanged(CollectionChange.ItemRemoved, key); 
       return true; 
      } 
      return false; 
     } 

     public bool Remove(KeyValuePair<K, V> item) 
     { 
      V currentValue; 
      if (_dictionary.TryGetValue(item.Key, out currentValue) && 
       Object.Equals(item.Value, currentValue) && _dictionary.Remove(item.Key)) 
      { 
       InvokeMapChanged(CollectionChange.ItemRemoved, item.Key); 
       return true; 
      } 
      return false; 
     } 

     public V this[K key] 
     { 
      get 
      { 
       return _dictionary[key]; 
      } 
      set 
      { 
       _dictionary[key] = value; 
       InvokeMapChanged(CollectionChange.ItemChanged, key); 
      } 
     } 

     public void Clear() 
     { 
      var priorKeys = _dictionary.Keys.ToArray(); 
      _dictionary.Clear(); 
      foreach (var key in priorKeys) 
      { 
       InvokeMapChanged(CollectionChange.ItemRemoved, key); 
      } 
     } 

     public ICollection<K> Keys 
     { 
      get { return _dictionary.Keys; } 
     } 

     public bool ContainsKey(K key) 
     { 
      return _dictionary.ContainsKey(key); 
     } 

     public bool TryGetValue(K key, out V value) 
     { 
      return _dictionary.TryGetValue(key, out value); 
     } 

     public ICollection<V> Values 
     { 
      get { return _dictionary.Values; } 
     } 

     public bool Contains(KeyValuePair<K, V> item) 
     { 
      return _dictionary.Contains(item); 
     } 

     public int Count 
     { 
      get { return _dictionary.Count; } 
     } 

     public bool IsReadOnly 
     { 
      get { return false; } 
     } 

     public IEnumerator<KeyValuePair<K, V>> GetEnumerator() 
     { 
      return _dictionary.GetEnumerator(); 
     } 

     System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
     { 
      return _dictionary.GetEnumerator(); 
     } 

     public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex) 
     { 
      if (array == null) throw new ArgumentNullException("array"); 
      int arraySize = array.Length; 
      foreach (var pair in _dictionary) 
      { 
       if (arrayIndex >= arraySize) break; 
       array[arrayIndex++] = pair; 
      } 
     } 
    } 

さらなる検査はの負荷を示しています新しいインターフェイスが定義されていますが、1つだけPropertySetクラスが実装されています。実際、これはかなり良いObservableDictionary自体のようです。しかし、MSが依然として私立ObservableDictionaryを生成する理由がなければならない。したがって、ここでは賛否両論を特定するためにさらに検討が必要です。

要するに、PropertySetまたはObservableDictionaryに基づく独自のIObservableMapは、現在のWindows 8および8プロジェクトの即時要件を解決する必要があります。しかし、古いフレームワーク(WPF 4とPhone 7.5)では、さらに多くの作業が必要です。

関連する問題