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

时间:2009-07-08 15:07:38

标签: c# wpf data-binding

我正在尝试在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");
        }
    }
}

}

不幸的是我仍然不知道如何传递“通用”词典对象..任何想法?

谢谢!

干杯

6 个答案:

答案 0 :(得分:35)

如果您真的想制作ObservableDictionary,我建议您创建一个同时实现IDictionaryINotifyCollectionChanged的类。你总是可以在内部使用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,因此会绕过你的事件。

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