.Net ObservableDictionary

He escrito la siguiente clase que implementa (o intenta!) Un diccionario con notificaciones:

public partial class ObservableDictionary : Dictionary, INotifyCollectionChanged { public ObservableDictionary() : base() { } public ObservableDictionary(int capacity) : base(capacity) { } public ObservableDictionary(IEqualityComparer comparer) : base(comparer) { } public ObservableDictionary(IDictionary dictionary) : base(dictionary) { } public ObservableDictionary(int capacity, IEqualityComparer comparer) : base(capacity, comparer) { } public ObservableDictionary(IDictionary dictionary, IEqualityComparer 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); } } } 

En otra clase, tengo un oyente para el evento MyObservableDictionary.CollectionChanged :

El problema que estoy teniendo es que el evento no se dispara. ¿Cómo puedo arreglar esto?

Sugiero que implemente IDictionary lugar de heredar Dictionary . Como tiene que usar new lugar de override , es posible que los métodos simplemente se invoquen en la clase base en lugar de su clase. Estaría tentado de usar un Dictionary internamente para hacer el almacenamiento real de datos.

De hecho, encontré esto: http://blogs.microsoft.co.il/blogs/shimmy/archive/2010/12/26/observabledictionary-lt-tkey-tvalue-gt-c.aspx

Microsoft ParallelExtensionsExtras proporciona esta clase que no solo es observable sino que también es concurrente:

Ahora disponible a través de Nuget: https://www.nuget.org/packages/ParallelExtensionsExtras/

Blog de la gira de Microsoft: https://blogs.msdn.microsoft.com/pfxteam/2010/04/04/a-tour-of-parallelextensionsextras/

Código de muestra de progtwigción paralela (código original de extensiones paralelas): https://code.msdn.microsoft.com/ParExtSamples

 //-------------------------------------------------------------------------- // // 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 { ///  /// Provides a thread-safe dictionary for use with data binding. ///  /// Specifies the type of the keys in this collection. /// Specifies the type of the values in this collection. [DebuggerDisplay("Count={Count}")] public class ObservableConcurrentDictionary : ICollection>, IDictionary, INotifyCollectionChanged, INotifyPropertyChanged { private readonly SynchronizationContext _context; private readonly ConcurrentDictionary _dictionary; ///  /// Initializes an instance of the ObservableConcurrentDictionary class. ///  public ObservableConcurrentDictionary() { _context = AsyncOperationManager.SynchronizationContext; _dictionary = new ConcurrentDictionary(); } /// Event raised when the collection changes. public event NotifyCollectionChangedEventHandler CollectionChanged; /// Event raised when a property on the collection changes. public event PropertyChangedEventHandler PropertyChanged; ///  /// Notifies observers of CollectionChanged or PropertyChanged of an update to the dictionary. ///  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); } } /// Attempts to add an item to the dictionary, notifying observers of any changes. /// The item to be added. /// Whether the add was successful. private bool TryAddWithNotification(KeyValuePair item) { return TryAddWithNotification(item.Key, item.Value); } /// Attempts to add an item to the dictionary, notifying observers of any changes. /// The key of the item to be added. /// The value of the item to be added. /// Whether the add was successful. private bool TryAddWithNotification(TKey key, TValue value) { bool result = _dictionary.TryAdd(key, value); if (result) NotifyObserversOfChange(); return result; } /// Attempts to remove an item from the dictionary, notifying observers of any changes. /// The key of the item to be removed. /// The value of the item removed. /// Whether the removal was successful. private bool TryRemoveWithNotification(TKey key, out TValue value) { bool result = _dictionary.TryRemove(key, out value); if (result) NotifyObserversOfChange(); return result; } /// Attempts to add or update an item in the dictionary, notifying observers of any changes. /// The key of the item to be updated. /// The new value to set for the item. /// Whether the update was successful. private void UpdateWithNotification(TKey key, TValue value) { _dictionary[key] = value; NotifyObserversOfChange(); } #region ICollection> Members void ICollection>.Add(KeyValuePair item) { TryAddWithNotification(item); } void ICollection>.Clear() { ((ICollection>)_dictionary).Clear(); NotifyObserversOfChange(); } bool ICollection>.Contains(KeyValuePair item) { return ((ICollection>)_dictionary).Contains(item); } void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { ((ICollection>)_dictionary).CopyTo(array, arrayIndex); } int ICollection>.Count { get { return ((ICollection>)_dictionary).Count; } } bool ICollection>.IsReadOnly { get { return ((ICollection>)_dictionary).IsReadOnly; } } bool ICollection>.Remove(KeyValuePair item) { TValue temp; return TryRemoveWithNotification(item.Key, out temp); } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return ((ICollection>)_dictionary).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return ((ICollection>)_dictionary).GetEnumerator(); } #endregion #region IDictionary Members public void Add(TKey key, TValue value) { TryAddWithNotification(key, value); } public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); } public ICollection 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 Values { get { return _dictionary.Values; } } public TValue this[TKey key] { get { return _dictionary[key]; } set { UpdateWithNotification(key, value); } } #endregion } } 

Su solución – Solucionado;)

 public class ObservableDictionary : Dictionary, INotifyCollectionChanged, INotifyPropertyChanged { public ObservableDictionary( ) : base( ) { } public ObservableDictionary(int capacity) : base(capacity) { } public ObservableDictionary(IEqualityComparer comparer) : base(comparer) { } public ObservableDictionary(IDictionary dictionary) : base(dictionary) { } public ObservableDictionary(int capacity, IEqualityComparer comparer) : base(capacity, comparer) { } public ObservableDictionary(IDictionary dictionary, IEqualityComparer 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(key, oldValue); base[key] = value; var newItem = new KeyValuePair(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(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(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); } } } 

Lancé el mío: https://www.nuget.org/packages/hellosam.net.collections/

Utiliza el árbol AVL para que las operaciones sean O (log N) en su lugar, donde la mayoría de las implementaciones que he visto usando List.indexOf () son O (N).

Incluso puede observar su elemento INotifyPropertyChanged y convertirlos en un evento de recostackción observable, para mantener la respuesta del grupo / clasificación de DataGrid al cambio.

He logrado encontrar una solución: solución alternativa

 public delegate void CollectionAlteredEventHander( object sender , EventArgs e); public partial class ObservableDictionary : Dictionary { /*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 observableDictionary, TKey key , ref int idx) { foreach (KeyValuePair 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 embargo, ya no implemento la interfaz INotifyCollectionChanged .