Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to create a custom observable collection using ConcurrentDictionary, INotifyCollectionChanged, INotifyPropertyChanged
    primarykey
    data
    text
    <p>I am trying to create an ObservableConcurrentDictionary. This object will be used in a multithreaded application, and it's data is used to populate a control via the controls ItemsSource property.</p> <p>This is the implementation i have come up with:</p> <pre><code>public sealed class ObservableConcurrentDictionary&lt;TKey, TValue&gt; : ConcurrentDictionary&lt;TKey, TValue&gt;, INotifyCollectionChanged, INotifyPropertyChanged { #region Constructors public ObservableConcurrentDictionary() : base() { } public ObservableConcurrentDictionary(IEnumerable&lt;KeyValuePair&lt;TKey, TValue&gt;&gt; collection) : base(collection) { } public ObservableConcurrentDictionary(IEqualityComparer&lt;TKey&gt; comparer) : base(comparer) { } public ObservableConcurrentDictionary(int concurrencyLevel, int capacity) : base(concurrencyLevel, capacity) { } public ObservableConcurrentDictionary(IEnumerable&lt;KeyValuePair&lt;TKey, TValue&gt;&gt; collection, IEqualityComparer&lt;TKey&gt; comparer) : base(collection, comparer) { } public ObservableConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer&lt;TKey&gt; comparer) : base(concurrencyLevel, capacity, comparer) { } public ObservableConcurrentDictionary(int concurrencyLevel, IEnumerable&lt;KeyValuePair&lt;TKey, TValue&gt;&gt; collection, IEqualityComparer&lt;TKey&gt; comparer) : base(concurrencyLevel, collection, comparer) { } #endregion #region Public Methods public new TValue AddOrUpdate(TKey key, Func&lt;TKey, TValue&gt; addValueFactory, Func&lt;TKey, TValue, TValue&gt; 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&lt;TKey, TValue&gt; 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 } </code></pre> <p>Unfortunately the solution does not work as intended - in fact, it doesn't work at all. Any ideas on what i am doing wrong or do any better solutions exist?</p> <p>Please note i CAN'T USE ObservableCollection, hence i have to write my own Observable collection.</p> <p><strong>EDIT: The working version is below. Hope this helps someone else with a similar problem.</strong></p> <pre><code>public sealed class ObservableConcurrentDictionary&lt;TKey, TValue&gt; : ConcurrentDictionary&lt;TKey, TValue&gt;, INotifyCollectionChanged, INotifyPropertyChanged { public ObservableConcurrentDictionary() : base() { } public ObservableConcurrentDictionary(IEnumerable&lt;KeyValuePair&lt;TKey, TValue&gt;&gt; collection) : base(collection) { } public ObservableConcurrentDictionary(IEqualityComparer&lt;TKey&gt; comparer) : base(comparer) { } public ObservableConcurrentDictionary(int concurrencyLevel, int capacity) : base(concurrencyLevel, capacity) { } public ObservableConcurrentDictionary(IEnumerable&lt;KeyValuePair&lt;TKey, TValue&gt;&gt; collection, IEqualityComparer&lt;TKey&gt; comparer) : base(collection, comparer) { } public ObservableConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer&lt;TKey&gt; comparer) : base(concurrencyLevel, capacity, comparer) { } public ObservableConcurrentDictionary(int concurrencyLevel, IEnumerable&lt;KeyValuePair&lt;TKey, TValue&gt;&gt; collection, IEqualityComparer&lt;TKey&gt; comparer) : base(concurrencyLevel, collection, comparer) { } public new TValue AddOrUpdate(TKey key, Func&lt;TKey, TValue&gt; addValueFactory, Func&lt;TKey, TValue, TValue&gt; 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&lt;TKey, TValue&gt; 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; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload