7

Estoy intentando crear un ObservableConcurrentDictionary. Este objeto se usará en una aplicación multiproceso, y sus datos se utilizan para completar un control a través de la propiedad de control ItemsSource.Cómo crear una colección observable personalizada utilizando ConcurrentDictionary, INotifyCollectionChanged, INotifyPropertyChanged

Esta es la aplicación que he llegado con:

public sealed class ObservableConcurrentDictionary<TKey, TValue> : ConcurrentDictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged 
{ 
    #region Constructors 

    public ObservableConcurrentDictionary() 
     : base() 
    { 

    } 

    public ObservableConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) 
     : base(collection) 
    { 

    } 


    public ObservableConcurrentDictionary(IEqualityComparer<TKey> comparer) 
     : base(comparer) 
    { 

    } 


    public ObservableConcurrentDictionary(int concurrencyLevel, int capacity) 
     : base(concurrencyLevel, capacity) 
    { 

    } 


    public ObservableConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) 
     : base(collection, comparer) 
    { 

    } 


    public ObservableConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer<TKey> comparer) 
     : base(concurrencyLevel, capacity, comparer) 
    { 

    } 

    public ObservableConcurrentDictionary(int concurrencyLevel, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) 
     : base(concurrencyLevel, collection, comparer) 
    { 

    } 

    #endregion 

    #region Public Methods 

    public new TValue AddOrUpdate(TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory) 
    { 
     // Stores the value 
     TValue value; 
     // If key exists 
     if (base.ContainsKey(key)) 
     { 
      // Update value and raise event 
      value = base.AddOrUpdate(key, addValueFactory, updateValueFactory); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace)); 
     } 
     // Else if key does not exist 
     else 
     { 
      // Add value and raise event 
      value = base.AddOrUpdate(key, addValueFactory, updateValueFactory); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add)); 
     } 
     // Returns the value 
     return value; 
    } 

    public void Clear() 
    { 
     // Clear dictionary 
     base.Clear(); 
     // Raise event 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
    } 

    public new TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory) 
    { 
     // Stores the value 
     TValue value; 
     // If key exists 
     if (base.ContainsKey(key)) 
      // Get value 
      value = base.GetOrAdd(key, valueFactory); 
     // Else if key does not exist 
     else 
     { 
      // Add value and raise event 
      value = base.GetOrAdd(key, valueFactory); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add)); 
     } 
     // Return value 
     return value; 
    } 

    public new TValue GetOrAdd(TKey key, TValue value) 
    { 
     // If key exists 
     if (base.ContainsKey(key)) 
      // Get value 
      base.GetOrAdd(key, value); 
     // Else if key does not exist 
     else 
     { 
      // Add value and raise event 
      base.GetOrAdd(key, value); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add)); 
     } 
     // Return value 
     return value; 
    } 

    public new bool TryAdd(TKey key, TValue value) 
    { 
     // Stores tryAdd 
     bool tryAdd; 
     // If added 
     if (tryAdd = base.TryAdd(key, value)) 
      // Raise event 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add)); 
     // Return tryAdd 
     return tryAdd; 
    } 

    public new bool TryRemove(TKey key, out TValue value) 
    { 
     // Stores tryRemove 
     bool tryRemove; 
     // If removed 
     if (tryRemove = base.TryRemove(key, out value)) 
      // Raise event 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove)); 
     // Return tryAdd 
     return tryRemove; 
    } 

    public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue) 
    { 
     // Stores tryUpdate 
     bool tryUpdate; 
     // If updated 
     if (tryUpdate = base.TryUpdate(key, newValue, comparisonValue)) 
      // Raise event 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace)); 
     // Return tryUpdate 
     return tryUpdate; 
    } 

    #endregion 

    #region Private Methods 

    private void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     if (CollectionChanged != null) 
      CollectionChanged(this, e); 
    } 

    #endregion 

    #region INotifyCollectionChanged Members 

    public event NotifyCollectionChangedEventHandler CollectionChanged; 

    #endregion 

    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 

    #endregion 
} 

Por desgracia, la solución no funciona según lo previsto - de hecho, no funciona en absoluto. ¿Alguna idea sobre lo que estoy haciendo mal o hay mejores soluciones?

Tenga en cuenta que NO PUEDO UTILIZAR ObservableCollection, por lo tanto, tengo que escribir mi propia colección Observable.

EDITAR: La versión de trabajo está debajo. Espero que esto ayude a alguien más con un problema similar.

public sealed class ObservableConcurrentDictionary<TKey, TValue> : ConcurrentDictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged 
{ 
    public ObservableConcurrentDictionary() 
     : base() 
    { 

    } 

    public ObservableConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) 
     : base(collection) 
    { 

    } 

    public ObservableConcurrentDictionary(IEqualityComparer<TKey> comparer) 
     : base(comparer) 
    { 

    } 

    public ObservableConcurrentDictionary(int concurrencyLevel, int capacity) 
     : base(concurrencyLevel, capacity) 
    { 

    } 

    public ObservableConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) 
     : base(collection, comparer) 
    { 

    } 

    public ObservableConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer<TKey> comparer) 
     : base(concurrencyLevel, capacity, comparer) 
    { 

    } 

    public ObservableConcurrentDictionary(int concurrencyLevel, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) 
     : base(concurrencyLevel, collection, comparer) 
    { 

    } 

    public new TValue AddOrUpdate(TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory) 
    { 
     // Stores the value 
     TValue value; 
     // If key exists 
     if (base.ContainsKey(key)) 
     { 
      // Update value and raise event 
      value = base.AddOrUpdate(key, addValueFactory, updateValueFactory); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value)); 
     } 
     // Else if key does not exist 
     else 
     { 
      // Add value and raise event 
      value = base.AddOrUpdate(key, addValueFactory, updateValueFactory); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 
     } 
     // Returns the value 
     return value; 
    } 

    public new void Clear() 
    { 
     // Clear dictionary 
     base.Clear(); 
     // Raise event 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
    } 

    public new TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory) 
    { 
     // Stores the value 
     TValue value; 
     // If key exists 
     if (base.ContainsKey(key)) 
      // Get value 
      value = base.GetOrAdd(key, valueFactory); 
     // Else if key does not exist 
     else 
     { 
      // Add value and raise event 
      value = base.GetOrAdd(key, valueFactory); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 
     } 
     // Return value 
     return value; 
    } 

    public new TValue GetOrAdd(TKey key, TValue value) 
    { 
     // If key exists 
     if (base.ContainsKey(key)) 
      // Get value 
      base.GetOrAdd(key, value); 
     // Else if key does not exist 
     else 
     { 
      // Add value and raise event 
      base.GetOrAdd(key, value); 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 
     } 
     // Return value 
     return value; 
    } 

    public new bool TryAdd(TKey key, TValue value) 
    { 
     // Stores tryAdd 
     bool tryAdd; 
     // If added 
     if (tryAdd = base.TryAdd(key, value)) 
      // Raise event 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 
     // Return tryAdd 
     return tryAdd; 
    } 

    public new bool TryRemove(TKey key, out TValue value) 
    { 
     // Stores tryRemove 
     bool tryRemove; 
     // If removed 
     if (tryRemove = base.TryRemove(key, out value)) 
      // Raise event 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, value)); 
     // Return tryAdd 
     return tryRemove; 
    } 

    public new bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue) 
    { 
     // Stores tryUpdate 
     bool tryUpdate; 
     // If updated 
     if (tryUpdate = base.TryUpdate(key, newValue, comparisonValue)) 
      // Raise event 
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newValue)); 
     // Return tryUpdate 
     return tryUpdate; 
    } 

    private void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     if (CollectionChanged != null) 
      CollectionChanged(this, e); 
    } 

    public event NotifyCollectionChangedEventHandler CollectionChanged; 

    public event PropertyChangedEventHandler PropertyChanged; 
} 
+0

"no funciona en absoluto" - no es una descripción válida del problema. Díganos qué errores está recibiendo, qué código está utilizando para probarlo y la razón por la que no puede usar ObservableCollection. – Euphoric

Respuesta

2

ir rápidamente a través de su código sin ningún eplanation de su lado sólo puedo adivinar. No creo que establecer Acción en NotifyCollectionChangedEventArgs sea suficiente. También hay NewItems, OldItems propiedades, que le dicen al suscriptor qué elementos cambiaron.

También tenga en cuenta que, si bien se trata de colecciones, muchos componentes de WPF solo admiten un único cambio de elemento a la vez a través de DataBinding.

+0

Mis disculpas por la vaga descripción. Ayer fue un día largo y frustrante. Me tienes moviéndome en la dirección correcta. Todo funciona correctamente ahora. ¡Gracias! – c0D3l0g1c

11

No pude obtener la muestra OPs para trabajar. Levanté una gran cantidad de troncos de cross threading exceptions todo el tiempo sin importar lo que intenté.

Sin embargo, dado que también necesitaba una colección de hilos seguros que implementara las interfaces INotifyCollectionChanged e INotifyPropertyChanged, busqué en Google y encontré una implementación de los chicos de Microsoft.

Descargue este archivo http://code.msdn.microsoft.com/Samples-for-Parallel-b4b76364 y busque ObservableConcurrentDictionary.cs en el archivo.

¡Funciona como un encanto!

+1

Ese enlace simplemente cambió mi vida. Gracias :) – Quanta

1

he desarrollado una versión ajustada de una ObservableConcurrentDictionnary, por favor comente/sugerir ...

... donde TValue: Object {use su clase en lugar del objeto ...}

Qurlet

using System; 
using System.Collections.Concurrent; 
using System.Collections.Generic; 
using System.Collections.Specialized; 
using System.ComponentModel; 

namespace Collections 
{ 
    public class ObservableConcurrentDictionary<TValue> : ConcurrentDictionary<Int32, TValue>, INotifyCollectionChanged, INotifyPropertyChanged 
     where TValue : Object , new() 
    { 
     public event NotifyCollectionChangedEventHandler CollectionChanged; 
     protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs changeAction) 
     { 
      var eh = CollectionChanged; 
      if (eh == null) return; 

      eh(this, changeAction); 

      OnPropertyChanged(); 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
     private void OnPropertyChanged() 
     { 
      var eh = PropertyChanged; 
      if (eh == null) return; 

      // All properties : Keys, Values, Count, IsEmpty 
      eh(this, new PropertyChangedEventArgs(null)); 
     } 

     #region Ctors 
     public ObservableConcurrentDictionary() 
      : base() 
     { 

     } 

     public ObservableConcurrentDictionary(IEnumerable<KeyValuePair<Int32, TValue>> collection) 
      : base(collection) 
     { 

     } 

     public ObservableConcurrentDictionary(IEqualityComparer<Int32> comparer) 
      : base(comparer) 
     { 

     } 

     public ObservableConcurrentDictionary(int concurrencyLevel, int capacity) 
      : base(concurrencyLevel, capacity) 
     { 

     } 

     public ObservableConcurrentDictionary(IEnumerable<KeyValuePair<Int32, TValue>> collection, IEqualityComparer<Int32> comparer) 
      : base(collection, comparer) 
     { 

     } 

     public ObservableConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer<Int32> comparer) 
      : base(concurrencyLevel, capacity, comparer) 
     { 

     } 

     public ObservableConcurrentDictionary(int concurrencyLevel, IEnumerable<KeyValuePair<Int32, TValue>> collection, IEqualityComparer<Int32> comparer) 
      : base(concurrencyLevel, collection, comparer) 
     { 

     } 
     #endregion 

     public new void Clear() 
     { 
      // Clear dictionary 
      base.Clear(); 
      // Raise event 
      OnCollectionChanged(changeAction: new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
     } 

     public new TValue AddOrUpdate(Int32 key, Func<Int32, TValue> addValueFactory, 
      Func<Int32, TValue, TValue> updateValueFactory) 
     { 
      bool isUpdated = false; 
      TValue oldValue = default(TValue); 

      TValue value = base.AddOrUpdate(key, addValueFactory, (k, v) => 
      { 
       isUpdated = true; 
       oldValue = v; 
       return updateValueFactory(k, v); 
      }); 

      if (isUpdated) OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, oldValue)); 

      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 
      return value; 
     } 

     public new TValue AddOrUpdate(Int32 key, TValue addValue, Func<Int32, TValue, TValue> updateValueFactory) 
     { 
      bool isUpdated = false; 
      TValue oldValue = default(TValue); 

      TValue value = base.AddOrUpdate(key, addValue, (k, v) => 
      { 
       isUpdated = true; 
       oldValue = v; 
       return updateValueFactory(k, v); 
      }); 

      if (isUpdated) OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, oldValue)); 

      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 
      return value; 
     } 

     public new TValue GetOrAdd(Int32 key, Func<Int32, TValue> addValueFactory) 
     { 
      bool isAdded = false; 

      TValue value = base.GetOrAdd(key, k => 
      { 
       isAdded = true; 
       return addValueFactory(k); 
      }); 

      if (isAdded) OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 

      return value; 
     } 

     public new TValue GetOrAdd(Int32 key, TValue value) 
     { 
      return GetOrAdd(key, k => value); 
     } 

     public new bool TryAdd(Int32 key, TValue value) 
     { 
      bool tryAdd = base.TryAdd(key, value); 

      if (tryAdd) OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)); 

      return tryAdd; 
     } 

     public new bool TryRemove(Int32 key, out TValue value) 
     { 
      // Stores tryRemove 
      bool tryRemove = base.TryRemove(key, out value); 

      // If removed raise event 
      if (tryRemove) OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, value)); 

      return tryRemove; 
     } 

     public new bool TryUpdate(Int32 key, TValue newValue, TValue comparisonValue) 
     { 
      // Stores tryUpdate 
      bool tryUpdate = base.TryUpdate(key, newValue, comparisonValue); 

      if (tryUpdate) OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newValue, comparisonValue)); 

      return tryUpdate; 
     } 

    } 
} 
Cuestiones relacionadas