DataBinding / WPF C#的通用可观察字典类

我正在尝试在C#中为WPF DataBinding创建一个Observable Dictionary Class。 我在这里找到了Andy的一个很好的例子: 双向数据绑定在WPF中的字典

据此,我试图将代码更改为以下内容:

class ObservableDictionary : ViewModelBase { public ObservableDictionary(Dictionary dictionary) { _data = dictionary; } private Dictionary _data; public Dictionary Data { get { return this._data; } } private KeyValuePair? _selectedKey = null; public KeyValuePair? 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"); } } } 

}

不幸的是我仍然不知道如何传递“一般”字典对象..任何想法?

谢谢!

干杯

如果你真的想制作一个ObservableDictionary ,我建议创建一个实现IDictionaryINotifyCollectionChanged 。 您可以随时在内部使用Dictionary来实现IDictionary的方法,这样您就不必自己重新实现它。

由于您完全了解内部Dictionary何时发生更改,因此您可以使用该知识来实现INotifyCollectionChanged

  • ObservableDictionary(Of TKey, TValue) – VB.NET
  • ObservableDictionary – C#

出于历史目的并将人们放在“当前”路径上……重要的是要知道Microsoft现在在Visual Studio 2012中的Windows Store“基本页面”模板中解决了这一要求。为了支持LayoutAwarePage,他们生成一个私有ObservableDictionary类。

但是,它们直接实现了一个新的IObservableMap接口,而不是IDictionary。 此接口添加了一个MapChanged事件和MapChangedEventHandler,它在Windows.Foundation.Collections命名空间中定义。

下面的代码段只是项目“Common”文件夹中生成的LayoutAwarePage.cs中的ObservableDictionary类:

  ///  /// Implementation of IObservableMap that supports reentrancy for use as a default view /// model. ///  private class ObservableDictionary : IObservableMap { private class ObservableDictionaryChangedEventArgs : IMapChangedEventArgs { public ObservableDictionaryChangedEventArgs(CollectionChange change, K key) { CollectionChange = change; Key = key; } public CollectionChange CollectionChange { get; private set; } public K Key { get; private set; } } private Dictionary _dictionary = new Dictionary(); public event MapChangedEventHandler 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 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 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 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 Values { get { return _dictionary.Values; } } public bool Contains(KeyValuePair item) { return _dictionary.Contains(item); } public int Count { get { return _dictionary.Count; } } public bool IsReadOnly { get { return false; } } public IEnumerator> GetEnumerator() { return _dictionary.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return _dictionary.GetEnumerator(); } public void CopyTo(KeyValuePair[] 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。 因此,需要进一步检查以确定优缺点。

简而言之,PropertySet或您自己的基于IObservableMap的ObservableDictionary应解决“当前”Windows 8和Phone 8项目的即时需求。 但是对于较旧的框架(WPF 4和Phone 7.5),还有更多工作要做。

我建议阅读以下文章,其中解释了如何实现可观察的字典,并且源代码可用于示例:

http://drwpf.com/blog/2007/09/16/can-i-bind-my-itemscontrol-to-a-dictionary/

Microsoft在MSFT.ParallelExtensionsExtras包中有一个可观察字典的实现,可通过Nuget获得: https ://www.nuget.org/packages/ParallelExtensionsExtras/

ObservableConcurrentDictionary

如果不使用某种forms的reflection,你就不能写出能够制作别人字典的东西,更不用说IDictionary了。 麻烦的是,Dictionary可能是一个子类,带有额外的mutator(比如,Sort,或Filter,或其他),它们不会调用Add和Remove,因此会绕过你的事件。

我相信代码生成框架允许你做这样的事情,但我不熟悉它们。