2009-07-08 86 views
25

我正在試圖在C#中爲WPF DataBinding創建一個Observable Dictionary Class。 我找到了一個很好的例子,從安迪在這裏:Two Way Data Binding With a Dictionary in WPFDataBinding的一般Observable字典類/ WPF 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 2009-07-08 15:17:39

+0

我有不同的詞典,例如:郵政編碼和城市。 我想要做的是: - 將數據(模型/字典)綁定到我的WPF ItemsControl,因此用戶可以例如更改郵政編碼的城市,模型會自動更新。不幸的是,只有OneWay綁定可能與「正常」字典,因爲我需要INotifyPropertyChanged。 - 創建ObservableDictionary,它實現INotifyPropertyChanged也包含着字典 – 2009-07-08 15:28:07

+0

該解決方案有:http://stackoverflow.com/questions/5663395/net-observabledictionary – 2014-07-22 01:52:21

回答

35

如果你真的想打一個ObservableDictionary,我建議創建一個實現既IDictionaryINotifyCollectionChanged類。您可以在內部始終使用Dictionary來實施IDictionary的方法,以便您不必自己重新實現。

由於您完全瞭解內部Dictionary何時更改,您可以使用該知識來實現​​INotifyCollectionChanged

0

你不能寫一些會使別人的字典,更不用說IDictionary,可觀察而不使用某種形式的反射。麻煩的是Dictionary可能是一個帶有額外的增變器的子類(比如Sort,Filter或者其他),它們不會調用Add和Remove,並繞過你的事件。

我相信代碼生成框架允許你做這樣的事情,但我不熟悉它們。

6

爲了歷史的目的和把人們放在「當前」的道路上......這是我的重要的是要知道微軟現在在Visual Studio 2012的Windows Store「基本頁面」模板中解決了這個需求。爲了支持LayoutAwarePage,他們生成了一個私有的ObservableDictionary類。

但是它們直接實現了一個新的IObservableMap接口而不是IDictionary。該接口添加了一個MapChanged事件和MapChangedEventHandler,它們在Windows.Foundation.Collections命名空間中定義。

下面的片段是剛剛從項目的「公共」文件夾中生成的LayoutAwarePage.cs的ObservableDictionary類:

/// <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; 
      } 
     } 
    } 

新Windows.Foundation.Collections命名空間的進一步檢查顯示的負載定義了新的接口,但只實現了一個PropertySet類。實際上,這看起來像是一個相當不錯的ObservableDictionary本身。但是爲什麼MS仍然會生成一個私有的ObservableDictionary。因此,需要進一步檢查以確定利弊。

總之,無論是屬性集或您自己的IObservableMap基於ObservableDictionary應該解決「當前」 Windows 8和Phone 8個的項目立即要求。然而對於較老的框架(WPF 4和Phone 7.5),還有更多的工作要做。