Observable Dictionary

13 Jul

As a fan of ObservableCollections, I have created an observable dictionary. I have provided the code below. I have implemented interfaces that should allow for WPF databinding. The reason I needed such a class is because I needed an event to indicate when the dictionary was updated. I kept this class small (it is just a wrapper over a dictionary).

public class ObservableDictionary<TKey, TValue> :

        IDictionary<TKey, TValue>,

        INotifyCollectionChanged,

        INotifyPropertyChanged

{

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    public event PropertyChangedEventHandler PropertyChanged;

 

    readonly IDictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();

 

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()

    {

        return _dictionary.GetEnumerator();

    }

 

    IEnumerator IEnumerable.GetEnumerator()

    {

        return GetEnumerator();

    }

 

    public void Add(KeyValuePair<TKey, TValue> item)

    {

        _dictionary.Add(item);

 

        if (CollectionChanged != null)

            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add));

 

        if (PropertyChanged != null)

        {

            PropertyChanged(this, new PropertyChangedEventArgs("Keys"));

            PropertyChanged(this, new PropertyChangedEventArgs("Values"));

        }

    }

 

    public void Clear()

    {

        int keysCount = _dictionary.Keys.Count;

 

        _dictionary.Clear();

 

        if (keysCount == 0) return; //dont trigger changed event if there was no change.

 

        if (CollectionChanged != null)

            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));

 

        if (PropertyChanged != null)

        {

            PropertyChanged(this, new PropertyChangedEventArgs("Keys"));

            PropertyChanged(this, new PropertyChangedEventArgs("Values"));

        }

    }

 

    public bool Contains(KeyValuePair<TKey, TValue> item)

    {

        return _dictionary.Contains(item);

    }

 

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)

    {

        _dictionary.CopyTo(array, arrayIndex);

    }

 

    public bool Remove(KeyValuePair<TKey, TValue> item)

    {

        bool remove = _dictionary.Remove(item);

 

        if (!remove) return false; //don’t trigger change events if there was no change.

 

        if (CollectionChanged != null)

            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove));

 

        if (PropertyChanged != null)

        {

            PropertyChanged(this, new PropertyChangedEventArgs("Keys"));

            PropertyChanged(this, new PropertyChangedEventArgs("Values"));

        }

 

        return true;

    }

 

    public int Count

    {

        get { return _dictionary.Count; }

    }

 

    public bool IsReadOnly

    {

        get { return _dictionary.IsReadOnly; }

    }

 

    public bool ContainsKey(TKey key)

    {

        return _dictionary.ContainsKey(key);

    }

 

    public void Add(TKey key, TValue value)

    {

        _dictionary.Add(key, value);

 

        if (CollectionChanged != null)

            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add));

 

        if (PropertyChanged != null)

        {

            PropertyChanged(this, new PropertyChangedEventArgs("Keys"));

            PropertyChanged(this, new PropertyChangedEventArgs("Values"));

        }

    }

 

    public bool Remove(TKey key)

    {

        bool remove = _dictionary.Remove(key);

 

        if (!remove) return false;

 

        if (CollectionChanged != null)

            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove));

 

        if (PropertyChanged != null)

        {

            PropertyChanged(this, new PropertyChangedEventArgs("Keys"));

            PropertyChanged(this, new PropertyChangedEventArgs("Values"));

        }

 

        return true;

    }

 

    public bool TryGetValue(TKey key, out TValue value)

    {

        return _dictionary.TryGetValue(key, out value);

    }

 

    public TValue this[TKey key]

    {

        get { return _dictionary[key]; }

        set

        {

            bool changed = _dictionary[key].Equals(value);

 

            if (!changed) return; //if there are no changes then we don’t need to update the value or trigger changed events.

 

            _dictionary[key] = value;

 

            if (CollectionChanged != null)

                CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace));

 

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs("Keys"));

                PropertyChanged(this, new PropertyChangedEventArgs("Values"));

            }

        }

    }

 

    public ICollection<TKey> Keys

    {

        get { return _dictionary.Keys; }

    }

 

    public ICollection<TValue> Values

    {

        get { return _dictionary.Values; }

    }

}

 

A link to another (Larger) implementation of an Observable Dictionary: http://www.drwpf.com/Blog/Default.aspx?tabid=36&EntryID=8

CC0
To the extent possible under law, Richard Wilburn has waived all copyright and related or neighboring rights to Observable Dictionary. This work is published from New Zealand.

Advertisements

6 Responses to “Observable Dictionary”

  1. Eckkrammer February 11, 2011 at 2:47 pm #

    Hello,

    This code segment has small bug, You will recceive an NotSupportedException if you use the Code like:
    CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace));

    See the comments of the NotifyCollectionChangedEventArgs class.

    • Daniel Portugal December 13, 2016 at 5:59 pm #

      I would try the following:

      public enum NotifyCollectionChangedAction : int
      {
      Add,Reset,Remove
      }

      public class NotifyCollectionChangedEventArgs : EventArgs
      {
      public NotifyCollectionChangedAction Type;

      public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction t)
      {
      this.Type = t;
      }
      }

      public class PropertyChangedEventArgs : EventArgs
      {
      public string property;
      public PropertyChangedEventArgs(string p)
      {
      this.property = p;
      }
      }

  2. rhwilburn February 11, 2011 at 7:55 pm #

    Thanks for the feedback. I will look into this when I next use it. If you care to offer a fix, that would be awesome.

  3. Benny Neugebauer June 18, 2012 at 8:45 pm #

    Thank you very much!! Very useful for Windows Phone applications! 🙂

  4. AJHope August 6, 2015 at 6:56 am #

    I want to catch ValueChanged event in a UserControl, what should I do?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: