我正在尝试在C#中为WPF DataBinding创建一个Observable Dictionary Class。 我在这里找到了安迪的一个很好的例子:Two Way Data Binding With a Dictionary in WPF
据此,我尝试将代码更改为以下内容:
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 :(得分:35)
如果您真的想制作ObservableDictionary
,我建议您创建一个同时实现IDictionary
和INotifyCollectionChanged
的类。你总是可以在内部使用Dictionary
来实现IDictionary
的方法,这样你就不必自己重新实现。
由于您完全了解内部Dictionary
何时发生变化,因此您可以使用该知识来实施INotifyCollectionChanged
。
答案 1 :(得分:19)
答案 2 :(得分:6)
出于历史目的,并将人们放在&#34;当前&#34;路径......了解微软现在在他们的Windows商店&#34;基本页面&#34;中解决这一要求非常重要。 Visual Studio 2012中的模板。为了支持LayoutAwarePage,它们生成一个私有的ObservableDictionary类。
然而,他们直接实现了一个新的IObservableMap接口而不是IDictionary。此接口添加了一个MapChanged事件和MapChangedEventHandler,它在Windows.Foundation.Collections命名空间中定义。
下面的代码段只是在&#34; Common&#34;中生成的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。因此,需要进一步检查以确定利弊。
简而言之,PropertySet或您自己的基于IObservableMap的ObservableDictionary应解决&#34; current&#34; Windows 8和Phone 8项目。但是对于较旧的框架(WPF 4和Phone 7.5),还有更多工作要做。
答案 3 :(得分:1)
我建议阅读以下文章,其中解释了如何实现可观察的字典,并且源代码可用于示例:
http://drwpf.com/blog/2007/09/16/can-i-bind-my-itemscontrol-to-a-dictionary/
答案 4 :(得分:1)
Microsoft通过Nuget在MSFT.ParallelExtensionsExtras
包中提供了一个可观察字典的实现:https://www.nuget.org/packages/ParallelExtensionsExtras/
ObservableConcurrentDictionary<TKey, TValue>
答案 5 :(得分:0)
如果没有使用某种形式的反射,你就不能写出会让其他人的词典,更不用说IDictionary,可观察的东西了。麻烦的是,Dictionary可能是一个子类,带有额外的mutator(比如,Sort,或者Filter,或其他),它们不会调用Add和Remove,因此会绕过你的事件。
我相信代码生成框架允许你做这样的事情,但我不熟悉它们。