Esta es la solución más válida que encomtrarás aportar, sin embargo obsérvala detenidamente y valora si se puede adaptar a tu proyecto.
Solución:
No pude hacer funcionar la muestra de OP. Levantó una carga troncal de excepciones de subprocesos cruzados todo el tiempo sin importar lo que intentara.
Sin embargo, dado que también necesitaba una colección segura para subprocesos que implemente las interfaces INotifyCollectionChanged e INotifyPropertyChanged, busqué en Google y encontré una implementación de los propios chicos de Microsoft.
Descargue este archivo http://code.msdn.microsoft.com/Samples-for-Parallel-b4b76364 y busque ObservableConcurrentDictionary.cs en el archivo.
¡Funciona de maravilla!
Revisando rápidamente su código sin ninguna explicación de su parte, solo puedo adivinar. No creo que establecer Acción en NotifyCollectionChangedEventArgs sea suficiente. también hay NewItems
, OldItems
properties, que le dicen al suscriptor qué elementos cambiaron.
Tenga en cuenta también que, si bien se trata de colecciones, muchos componentes de WPF solo admiten el cambio de un solo elemento a la vez a través de DataBinding.
Desarrollé una versión ajustada de un ObservableConcurrentDictionnary, comente/sugiera…
… donde TValue : Object usa tu clase en lugar de Object…
qurlet
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
namespace Collections
public class ObservableConcurrentDictionary : ConcurrentDictionary, 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> collection)
: base(collection)
public ObservableConcurrentDictionary(IEqualityComparer comparer)
: base(comparer)
public ObservableConcurrentDictionary(int concurrencyLevel, int capacity)
: base(concurrencyLevel, capacity)
public ObservableConcurrentDictionary(IEnumerable> collection, IEqualityComparer comparer)
: base(collection, comparer)
public ObservableConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer comparer)
: base(concurrencyLevel, capacity, comparer)
public ObservableConcurrentDictionary(int concurrencyLevel, IEnumerable> collection, IEqualityComparer 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 addValueFactory,
Func 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 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 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;
Si posees alguna cuestión o capacidad de beneficiar nuestro división puedes realizar una aclaración y con deseo lo leeremos.