none
如何实现一个ObservableDictionary? RRS feed

  • 问题

  • public class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged
        {
            public event NotifyCollectionChangedEventHandler CollectionChanged;
            private void NotifyCollectionChanged(NotifyCollectionChangedEventArgs e)
            {
                if (CollectionChanged != null)
                {
                    CollectionChanged(this, e);
                }
            }
    ......

    这样写了一个ObservableDictionary,可是if (CollectionChanged != null)这行的结果永远是false,也就是CollectionChanged总是null的。这是怎么回事呢?怎么才能实现一个ObservableDictionary?
    2012年9月27日 15:05

答案

  • 新建一个Grid App 模板的项目,从他的 Common\LayoutAwarePage.cs 中可以找到一个实现,你可以参考,直接实现 IObservableMap<K, V> 接口。

    C++种使用 Map<K,V> 即可。他已实现 IObservableMap<K,V>


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    • 已标记为答案 [-] 2012年9月28日 14:19
    2012年9月28日 5:54
    版主
  • 我上面的2个回复其实已经说明了 ,CollectionChanged事件是用于集合的, 而字典中应该是使用 MapChanged事件用来做通知事件的.

    我第一次的回复是看错了, 因为你在问CollectionChanged事件, 我以为你是要实现自定义集合, 后面看到你要实现的自定义的字典, 你看我贴的代码中,

    改变事件就是调用的MapChanged. 这个事件在 IObservableMap<K,V>借口中已经定义了.

    你需要实践自定义的字典, 只需要实现 IObservableMap<K,V>接口就可以了.


    Thanks! Damon.Tian

    • 已标记为答案 [-] 2012年9月28日 14:19
    2012年9月28日 12:12

全部回复

  • 顺便再请教一个问题,在C++里有没有ObservableCollection,如果没有的话要怎么实现呢?

    2012年9月27日 16:41
  • 这样实现时没有问题的,在metro中使用这个类,如果实现了INotifyCollectionChanged接口,就会给绑定CollectionChanged事件。所以你看到不会为null,但是作为一个单存的类,实现的时候你不能保证你的事件一定会有绑定,所以使用之前都需要判断。


    Thanks! Damon.Tian

    2012年9月28日 0:48
  • 新建一个Grid App 模板的项目,从他的 Common\LayoutAwarePage.cs 中可以找到一个实现,你可以参考,直接实现 IObservableMap<K, V> 接口。

    C++种使用 Map<K,V> 即可。他已实现 IObservableMap<K,V>


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    • 已标记为答案 [-] 2012年9月28日 14:19
    2012年9月28日 5:54
    版主
  • 请问,怎么是IObservableMap<K, V>接口呢?不用INotifyCollectionChanged么?是不是不支持CollectionChanged?

    2012年9月28日 6:38
  • 当然不是,我只是提供一个额外的思路。


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    2012年9月28日 7:27
    版主
  • 我看错了,以为你要实现一个自定义的ObservableCollection,ObservableDictionary<K,T>的微软的模版里面有实现,实现IObservableMap<K, V>即可,

    private class ObservableDictionary<K, V> : IObservableMap<K, V>
            {
                private class ObservableDictionaryChangedEventArgs : IMapChangedEventArgs<K>
                {
                    public ObservableDictionaryChangedEventArgs(CollectionChange change, K key)
                    {
                        this.CollectionChange = change;
                        this.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)
                {
                    this._dictionary.Add(key, value);
                    this.InvokeMapChanged(CollectionChange.ItemInserted, key);
                }
    
                public void Add(KeyValuePair<K, V> item)
                {
                    this.Add(item.Key, item.Value);
                }
    
                public bool Remove(K key)
                {
                    if (this._dictionary.Remove(key))
                    {
                        this.InvokeMapChanged(CollectionChange.ItemRemoved, key);
                        return true;
                    }
                    return false;
                }
    
                public bool Remove(KeyValuePair<K, V> item)
                {
                    V currentValue;
                    if (this._dictionary.TryGetValue(item.Key, out currentValue) &&
                        Object.Equals(item.Value, currentValue) && this._dictionary.Remove(item.Key))
                    {
                        this.InvokeMapChanged(CollectionChange.ItemRemoved, item.Key);
                        return true;
                    }
                    return false;
                }
    
                public V this[K key]
                {
                    get
                    {
                        return this._dictionary[key];
                    }
                    set
                    {
                        this._dictionary[key] = value;
                        this.InvokeMapChanged(CollectionChange.ItemChanged, key);
                    }
                }
    
                public void Clear()
                {
                    var priorKeys = this._dictionary.Keys.ToArray();
                    this._dictionary.Clear();
                    foreach (var key in priorKeys)
                    {
                        this.InvokeMapChanged(CollectionChange.ItemRemoved, key);
                    }
                }
    
                public ICollection<K> Keys
                {
                    get { return this._dictionary.Keys; }
                }
    
                public bool ContainsKey(K key)
                {
                    return this._dictionary.ContainsKey(key);
                }
    
                public bool TryGetValue(K key, out V value)
                {
                    return this._dictionary.TryGetValue(key, out value);
                }
    
                public ICollection<V> Values
                {
                    get { return this._dictionary.Values; }
                }
    
                public bool Contains(KeyValuePair<K, V> item)
                {
                    return this._dictionary.Contains(item);
                }
    
                public int Count
                {
                    get { return this._dictionary.Count; }
                }
    
                public bool IsReadOnly
                {
                    get { return false; }
                }
    
                public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
                {
                    return this._dictionary.GetEnumerator();
                }
    
                System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
                {
                    return this._dictionary.GetEnumerator();
                }
    
                public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex)
                {
                    int arraySize = array.Length;
                    foreach (var pair in this._dictionary)
                    {
                        if (arrayIndex >= arraySize) break;
                        array[arrayIndex++] = pair;
                    }
                }
            }


    Thanks! Damon.Tian

    2012年9月28日 7:32
  • 我不是想问怎么实现ObservableDictionary,我想问的是为什么CollectionChanged总是null?也就是我的那种实现错在哪里,为什么无效,没有实现集合更改通知。

    public class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged { public event NotifyCollectionChangedEventHandler CollectionChanged; private void NotifyCollectionChanged(NotifyCollectionChangedEventArgs e) { if (CollectionChanged != null) { CollectionChanged(this, e); } } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string info) { if (PropertyChanged != null && info != null) { PropertyChanged(this, new PropertyChangedEventArgs(info));

    } } public new void Add(TKey Key, TValue Value) { base.Add(Key, Value); NotifyPropertyChanged("Keys"); NotifyPropertyChanged("Values"); NotifyPropertyChanged("Count"); NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new KeyValuePair<TKey, TValue>(Key, Value), this.Count - 1)); } }

    以上代码在运行的时候,if (CollectionChanged != null)这行的判断结果永远是false,结果就是没有实现通知。


    • 已编辑 [-] 2012年9月28日 8:55
    2012年9月28日 8:52
  • 我上面的2个回复其实已经说明了 ,CollectionChanged事件是用于集合的, 而字典中应该是使用 MapChanged事件用来做通知事件的.

    我第一次的回复是看错了, 因为你在问CollectionChanged事件, 我以为你是要实现自定义集合, 后面看到你要实现的自定义的字典, 你看我贴的代码中,

    改变事件就是调用的MapChanged. 这个事件在 IObservableMap<K,V>借口中已经定义了.

    你需要实践自定义的字典, 只需要实现 IObservableMap<K,V>接口就可以了.


    Thanks! Damon.Tian

    • 已标记为答案 [-] 2012年9月28日 14:19
    2012年9月28日 12:12
  • 再请问一下,C++里对应ObservableDictionary的是Map<K,V>对吧,那对应ObservableCollection的是什么呢?

    2012年9月28日 15:10
  • 烦请大家帮忙解答一下。

    2012年10月1日 6:36
  • http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh700103.aspx

    IVector 和 Vector


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    2012年10月1日 8:38
    版主
  • C++中使用Vector,自定义的话是实现IObservableVector接口。

    Thanks! Damon.Tian

    2012年10月1日 8:43