.NET ObservableDictionary
我已经写了下面的类来实现(或试图!)带有通知的字典:
public partial class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, INotifyCollectionChanged { public ObservableDictionary() : base() { } public ObservableDictionary(int capacity) : base(capacity) { } public ObservableDictionary(IEqualityComparer<TKey> comparer) : base(comparer) { } public ObservableDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary) { } public ObservableDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer) { } public ObservableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : base(dictionary, comparer) { } public event NotifyCollectionChangedEventHandler CollectionChanged; public new TValue this[TKey key] { get { return base[key]; } set { OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, key, 0)); base[key] = value; } } public new void Add(TKey key, TValue value) { base.Add(key, value); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, key, 0)); } public new bool Remove(TKey key) { bool x = base.Remove(key); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, key, 0)); return x; } public new void Clear() { base.Clear(); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (CollectionChanged != null) { CollectionChanged(this, e); } } }
在另一个类中,我有一个MyObservableDictionary.CollectionChanged
事件的监听器:
我遇到的问题是事件不会触发。 我该如何解决这个问题?
我build议你实现IDictionary<TKey, TValue>
而不是从Dictionary<TKey, TValue>
inheritance。 既然你必须使用new
而不是override
那么可能只是在基类而不是你的类上调用这些方法。 我会试图在内部使用Dictionary<TKey, TValue>
来实际存储数据。
事实上,我发现这个: http : //blogs.microsoft.co.il/blogs/shimmy/archive/2010/12/26/observabledictionary-lt-tkey-tvalue-gt-c.aspx
https://code.msdn.microsoft.com/windowsdesktop/Samples-for-Parallel-b4b76364
Microsoft ParallelExtensionsExtras提供的这个类不仅是可观察的,而且是并发的:
//-------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: ObservableConcurrentDictionary.cs // //-------------------------------------------------------------------------- using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Threading; using System.Diagnostics; namespace System.Collections.Concurrent { /// <summary> /// Provides a thread-safe dictionary for use with data binding. /// </summary> /// <typeparam name="TKey">Specifies the type of the keys in this collection.</typeparam> /// <typeparam name="TValue">Specifies the type of the values in this collection.</typeparam> [DebuggerDisplay("Count={Count}")] public class ObservableConcurrentDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged { private readonly SynchronizationContext _context; private readonly ConcurrentDictionary<TKey, TValue> _dictionary; /// <summary> /// Initializes an instance of the ObservableConcurrentDictionary class. /// </summary> public ObservableConcurrentDictionary() { _context = AsyncOperationManager.SynchronizationContext; _dictionary = new ConcurrentDictionary<TKey, TValue>(); } /// <summary>Event raised when the collection changes.</summary> public event NotifyCollectionChangedEventHandler CollectionChanged; /// <summary>Event raised when a property on the collection changes.</summary> public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// Notifies observers of CollectionChanged or PropertyChanged of an update to the dictionary. /// </summary> private void NotifyObserversOfChange() { var collectionHandler = CollectionChanged; var propertyHandler = PropertyChanged; if (collectionHandler != null || propertyHandler != null) { _context.Post(s => { if (collectionHandler != null) { collectionHandler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } if (propertyHandler != null) { propertyHandler(this, new PropertyChangedEventArgs("Count")); propertyHandler(this, new PropertyChangedEventArgs("Keys")); propertyHandler(this, new PropertyChangedEventArgs("Values")); } }, null); } } /// <summary>Attempts to add an item to the dictionary, notifying observers of any changes.</summary> /// <param name="item">The item to be added.</param> /// <returns>Whether the add was successful.</returns> private bool TryAddWithNotification(KeyValuePair<TKey, TValue> item) { return TryAddWithNotification(item.Key, item.Value); } /// <summary>Attempts to add an item to the dictionary, notifying observers of any changes.</summary> /// <param name="key">The key of the item to be added.</param> /// <param name="value">The value of the item to be added.</param> /// <returns>Whether the add was successful.</returns> private bool TryAddWithNotification(TKey key, TValue value) { bool result = _dictionary.TryAdd(key, value); if (result) NotifyObserversOfChange(); return result; } /// <summary>Attempts to remove an item from the dictionary, notifying observers of any changes.</summary> /// <param name="key">The key of the item to be removed.</param> /// <param name="value">The value of the item removed.</param> /// <returns>Whether the removal was successful.</returns> private bool TryRemoveWithNotification(TKey key, out TValue value) { bool result = _dictionary.TryRemove(key, out value); if (result) NotifyObserversOfChange(); return result; } /// <summary>Attempts to add or update an item in the dictionary, notifying observers of any changes.</summary> /// <param name="key">The key of the item to be updated.</param> /// <param name="value">The new value to set for the item.</param> /// <returns>Whether the update was successful.</returns> private void UpdateWithNotification(TKey key, TValue value) { _dictionary[key] = value; NotifyObserversOfChange(); } #region ICollection<KeyValuePair<TKey,TValue>> Members void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) { TryAddWithNotification(item); } void ICollection<KeyValuePair<TKey, TValue>>.Clear() { ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Clear(); NotifyObserversOfChange(); } bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Contains(item); } void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).CopyTo(array, arrayIndex); } int ICollection<KeyValuePair<TKey, TValue>>.Count { get { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Count; } } bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly { get { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).IsReadOnly; } } bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) { TValue temp; return TryRemoveWithNotification(item.Key, out temp); } #endregion #region IEnumerable<KeyValuePair<TKey,TValue>> Members IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).GetEnumerator(); } #endregion #region IDictionary<TKey,TValue> Members public void Add(TKey key, TValue value) { TryAddWithNotification(key, value); } public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); } public ICollection<TKey> Keys { get { return _dictionary.Keys; } } public bool Remove(TKey key) { TValue temp; return TryRemoveWithNotification(key, out temp); } public bool TryGetValue(TKey key, out TValue value) { return _dictionary.TryGetValue(key, out value); } public ICollection<TValue> Values { get { return _dictionary.Values; } } public TValue this[TKey key] { get { return _dictionary[key]; } set { UpdateWithNotification(key, value); } } #endregion } }
您的解决scheme – 修正;)
public class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged { public ObservableDictionary( ) : base( ) { } public ObservableDictionary(int capacity) : base(capacity) { } public ObservableDictionary(IEqualityComparer<TKey> comparer) : base(comparer) { } public ObservableDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary) { } public ObservableDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer) { } public ObservableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : base(dictionary, comparer) { } public event NotifyCollectionChangedEventHandler CollectionChanged; public event PropertyChangedEventHandler PropertyChanged; public new TValue this[TKey key] { get { return base[key]; } set { TValue oldValue; bool exist = base.TryGetValue(key, out oldValue); var oldItem = new KeyValuePair<TKey, TValue>(key, oldValue); base[key] = value; var newItem = new KeyValuePair<TKey, TValue>(key, value); if (exist) { this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newItem, oldItem, base.Keys.ToList( ).IndexOf(key))); } else { this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newItem, base.Keys.ToList( ).IndexOf(key))); this.OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count))); } } } public new void Add(TKey key, TValue value) { if (!base.ContainsKey(key)) { var item = new KeyValuePair<TKey, TValue>(key, value); base.Add(key, value); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, base.Keys.ToList( ).IndexOf(key))); this.OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count))); } } public new bool Remove(TKey key) { TValue value; if (base.TryGetValue(key, out value)) { var item = new KeyValuePair<TKey, TValue>(key, base[key]); bool result = base.Remove(key); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, base.Keys.ToList( ).IndexOf(key))); this.OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count))); return result; } return false; } public new void Clear( ) { base.Clear( ); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); this.OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count))); } protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (this.CollectionChanged != null) { this.CollectionChanged(this, e); } } protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { if (this.PropertyChanged != null) { this.PropertyChanged(this, e); } } }
我推出了自己的: https : //www.nuget.org/packages/hellosam.net.collections/
它使用AVL树,所以操作是O(log N),而我在List.indexOf()中看到的大多数实现都是O(N)。
它甚至可以观察到你的项目INotifyPropertyChanged并将它们转换为一个可观察的集合事件,所以保持DataGridsorting/组响应的变化。
我设法find解决方法 – 解决方法
public delegate void CollectionAlteredEventHander( object sender , EventArgs e); public partial class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue> { /*Class contructors*/ public event CollectionAlteredEventHander CollectionAltered; public new TValue this[TKey key] { get { return base[key]; } set { OnCollectionAltered(new EventArgs()); base[key] = value; } } public new void Add(TKey key, TValue value) { int idx = 0; if (!TryGetKeyIndex(this, key, ref idx)) { base.Add(key, value); OnCollectionAltered(new EventArgs()); } } public new bool Remove(TKey key) { int idx = 0; if( TryGetKeyIndex( this ,key, ref idx)) { OnCollectionAltered(new EventArgs()); return base.Remove(key); } return false; } private bool TryGetKeyIndex(ObservableDictionary<TKey, TValue> observableDictionary, TKey key , ref int idx) { foreach (KeyValuePair<TKey, TValue> pair in observableDictionary) { if (pair.Key.Equals(key)) { return true; } idx++; } return false; } public new void Clear() { OnCollectionAltered(new EventArgs()); base.Clear(); } protected virtual void OnCollectionAltered(EventArgs e) { if (CollectionAltered != null) { CollectionAltered(this, e); } } }
虽然我不再实现INotifyCollectionChanged
接口。