【问题标题】:General Observable Dictionary Class for DataBinding/WPF C#DataBinding/WPF C# 的通用 Observable 字典类
【发布时间】:2009-07-08 15:07:38
【问题描述】:

我正在尝试在 C# 中为 WPF DataBinding 创建一个可观察字典类。 我在这里找到了 Andy 的一个很好的例子: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");
        }
    }
}

}

不幸的是,我仍然不知道如何传递“通用”字典对象..有什么想法吗?

谢谢!

干杯

【问题讨论】:

  • 您能否详细说明您要做什么?当你说“通过通用字典......”时,你能展示一个你希望能够编写的代码示例吗?
  • 我有不同的字典,例如邮政编码和城市。我想要做的是: - 将数据(模型/字典)绑定到我的 WPF ItemsControl,以便用户可以例如更改邮政编码所在的城市,模型会自动更新。不幸的是,“普通”字典只能使用 OneWay-Binding,因为我需要 INotifyPropertyChanged。 - 创建一个 ObservableDictionary,它实现了 INotifyPropertyChanged 并且还包含一个字典

标签: c# wpf data-binding


【解决方案1】:

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

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

【讨论】:

【解决方案2】:

【讨论】:

  • 我似乎无法实现 INotifyCollectionChanged。它说缺少装配。我在您的帖子顶部导入了所有程序集(C#),我有 .NET 3.5,但找不到它。有什么想法吗?
  • 您导入了命名空间,但可能缺少对关键程序集的引用。确保在您的项目中引用了程序集 System.dll。参见示例here
  • 链接好像坏了。
  • 链接失效了。
【解决方案3】:

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

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

下面的 sn-p 只是你项目的“Common”文件夹中生成的 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 应该可以解决“当前”Windows 8 和 Phone 8 项目的即时需求。但是,对于较旧的框架(WPF 4 和 Phone 7.5),还有更多工作要做。

【讨论】:

    【解决方案4】:

    Microsoft 在通过 Nuget 提供的 MSFT.ParallelExtensionsExtras 包中实现了可观察字典:https://www.nuget.org/packages/ParallelExtensionsExtras/

    ObservableConcurrentDictionary&lt;TKey, TValue&gt;

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

        如果不使用某种形式的反射,您无法编写可以使别人的字典(更不用说 IDictionary)可观察的东西了。问题在于 Dictionary 可能是一个子类,其中包含不调用 Add 和 Remove 并因此绕过您的事件的其他变量(例如,Sort 或 Filter 等)。

        我相信存在允许您执行此类操作的代码生成框架,但我不熟悉它们。

        【讨论】:

          猜你喜欢
          • 2013-03-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多