-1

I am trying to update a Listbox whenever a new 'key','value' is added to a dictionary.

I have a class that implements IDictionary and INotifyPropertyChanged ( copied from MSDN) and it has a method Add. (I have not added other methods to keep the questions short);

public class SimpleDictionary : IDictionary, INotifyPropertyChanged
  {
      public DictionaryEntry[] items;
      public Int32 ItemsInUse = 0;

     public void Add(object key, object value)
        {
            // Add the new key/value pair even if this key already exists in the dictionary.
            if (ItemsInUse == items.Length)
                throw new InvalidOperationException("The dictionary cannot hold any more items.");
            items[ItemsInUse++] = new DictionaryEntry(key, value);
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("key"));

        }

}

In Main void method I have following:

public static SimpleDictionary clients = new SimpleDictionary(3);
     static void Main()
            {
                clients.Add("key1", "Value1");
                display_List();
                clients.PropertyChanged += Clients_PropertyChanged;
            }

     private static void Clients_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                MessageBox.Show("Dictionary changed: "+e.PropertyName);
            }
     static void display_List()
            {
                try {

                    form_m.listBox1.DataSource = new BindingSource(clients,null);

                    form_m.listBox1.DisplayMember = "key";

                }
                catch (Exception e) {

                    form_m.Program_console_1("Displat Binding Error: "+e.ToString());

                }


            }
    public static void Update_Dictionary(object sender, System.EventArgs e)
            {

                clients.Add("key3","Value3");

            }

When the program starts listBox1 is initialized and "key1","value" added to 'clients'. Method display_List binds clients and displays all the keys.

When I invoke Update_Dictionary method "key2","value2" are added and Clients_PropertyChanged is fired. However, listbox1 does not reflect the new key added i.e "key2". It still only shows "key1".

If I add the Datasource again then "key1" and "key2" are shown. What needs to be done so that listbox is updated when Clients_PropertyChanged is called automatically?

UPDATE: Tried using INotifyCollectionChanged still the same problem

He is the complete class I am using

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

namespace x_server
{

    // This class implements a simple dictionary using an array of DictionaryEntry objects (key/value pairs).
    class ObservableDictionary<TKey, TValue> : IDictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged
    {
        private const string CountString = "Count";
        private const string IndexerName = "Item[]";
        private const string KeysName = "Keys";
        private const string ValuesName = "Values";

        private IDictionary<TKey, TValue> _Dictionary;
        protected IDictionary<TKey, TValue> Dictionary
        {
            get { return _Dictionary; }
        }

        #region Constructors
        public ObservableDictionary()
        {
            _Dictionary = new Dictionary<TKey, TValue>();
        }
        public ObservableDictionary(IDictionary<TKey, TValue> dictionary)
        {
            _Dictionary = new Dictionary<TKey, TValue>(dictionary);
        }
        public ObservableDictionary(IEqualityComparer<TKey> comparer)
        {
            _Dictionary = new Dictionary<TKey, TValue>(comparer);
        }
        public ObservableDictionary(int capacity)
        {
            _Dictionary = new Dictionary<TKey, TValue>(capacity);
        }
        public ObservableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
        {
            _Dictionary = new Dictionary<TKey, TValue>(dictionary, comparer);
        }
        public ObservableDictionary(int capacity, IEqualityComparer<TKey> comparer)
        {
            _Dictionary = new Dictionary<TKey, TValue>(capacity, comparer);
        }
        #endregion

        #region IDictionary<TKey,TValue> Members

        public void Add(TKey key, TValue value)
        {
            Insert(key, value, true);
        }

        public bool ContainsKey(TKey key)
        {
            return Dictionary.ContainsKey(key);
        }

        public ICollection<TKey> Keys
        {
            get { return Dictionary.Keys; }
        }

        public bool Remove(TKey key)
        {
            if (key == null) throw new ArgumentNullException("key");

            TValue value;
            Dictionary.TryGetValue(key, out value);
            var removed = Dictionary.Remove(key);
            if (removed)
                //OnCollectionChanged(NotifyCollectionChangedAction.Remove, new KeyValuePair<TKey, TValue>(key, value));
                OnCollectionChanged();

            return removed;
        }


        public bool TryGetValue(TKey key, out TValue value)
        {
            return Dictionary.TryGetValue(key, out value);
        }


        public ICollection<TValue> Values
        {
            get { return Dictionary.Values; }
        }


        public TValue this[TKey key]
        {
            get
            {
                return Dictionary[key];
            }
            set
            {
                Insert(key, value, false);
            }
        }


        #endregion


        #region ICollection<KeyValuePair<TKey,TValue>> Members


        public void Add(KeyValuePair<TKey, TValue> item)
        {
            Insert(item.Key, item.Value, true);
        }


        public void Clear()
        {
            if (Dictionary.Count > 0)
            {
                Dictionary.Clear();
                OnCollectionChanged();
            }
        }


        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 int Count
        {
            get { return Dictionary.Count; }
        }


        public bool IsReadOnly
        {
            get { return Dictionary.IsReadOnly; }
        }


        public bool Remove(KeyValuePair<TKey, TValue> item)
        {
            return Remove(item.Key);
        }


        #endregion


        #region IEnumerable<KeyValuePair<TKey,TValue>> Members


        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            return Dictionary.GetEnumerator();
        }


        #endregion


        #region IEnumerable Members


        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable)Dictionary).GetEnumerator();
        }


        #endregion


        #region INotifyCollectionChanged Members


        public event NotifyCollectionChangedEventHandler CollectionChanged;


        #endregion


        #region INotifyPropertyChanged Members


        public event PropertyChangedEventHandler PropertyChanged;


        #endregion


        public void AddRange(IDictionary<TKey, TValue> items)
        {
            if (items == null) throw new ArgumentNullException("items");


            if (items.Count > 0)
            {
                if (Dictionary.Count > 0)
                {
                    if (items.Keys.Any((k) => Dictionary.ContainsKey(k)))
                        throw new ArgumentException("An item with the same key has already been added.");
                    else
                        foreach (var item in items) Dictionary.Add(item);
                }
                else
                    _Dictionary = new Dictionary<TKey, TValue>(items);


                OnCollectionChanged(NotifyCollectionChangedAction.Add, items.ToArray());
            }
        }


        private void Insert(TKey key, TValue value, bool add)
        {
            if (key == null) throw new ArgumentNullException("key");


            TValue item;
            if (Dictionary.TryGetValue(key, out item))
            {
                if (add) throw new ArgumentException("An item with the same key has already been added.");
                if (Equals(item, value)) return;
                Dictionary[key] = value;


                OnCollectionChanged(NotifyCollectionChangedAction.Replace, new KeyValuePair<TKey, TValue>(key, value), new KeyValuePair<TKey, TValue>(key, item));
            }
            else
            {
                Dictionary[key] = value;

                OnCollectionChanged(NotifyCollectionChangedAction.Add, new KeyValuePair<TKey, TValue>(key, value));
            }
        }


        private void OnPropertyChanged()
        {
            OnPropertyChanged(CountString);
            OnPropertyChanged(IndexerName);
            OnPropertyChanged(KeysName);
            OnPropertyChanged(ValuesName);
        }


        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }


        private void OnCollectionChanged()
        {
            OnPropertyChanged();
            if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }


        private void OnCollectionChanged(NotifyCollectionChangedAction action, KeyValuePair<TKey, TValue> changedItem)
        {
            OnPropertyChanged();
            if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, changedItem));
        }


        private void OnCollectionChanged(NotifyCollectionChangedAction action, KeyValuePair<TKey, TValue> newItem, KeyValuePair<TKey, TValue> oldItem)
        {
            OnPropertyChanged();
            if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, newItem, oldItem));
        }


        private void OnCollectionChanged(NotifyCollectionChangedAction action, IList newItems)
        {
            OnPropertyChanged();
            if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, newItems));
        }
    }
}   
user2288650
  • 412
  • 1
  • 6
  • 23
  • Your property notification makes no sense. Your code for `SimpleDictionary` currently tries to tell through the PropertyChanged event that its `Key` property has changed. The thing is, `SimpleDictionary` doesn't have a `Key` property, hence why the the property notification does not make any sense. Not sure if WinForms ListBox supports it, but you might try a collection that implements `INotifyCollectionChanged`. For example something like an ObservableDictionary (not part of the .NET framework but there are tons of implementations for it floating around in the interwebs...) –  Jan 12 '19 at 20:23
  • Possible duplicate of [How to bind Dictionary to ListBox in winforms](https://stackoverflow.com/questions/1506987/how-to-bind-dictionary-to-listbox-in-winforms) – Ňɏssa Pøngjǣrdenlarp Jan 12 '19 at 20:38
  • 2
    [Databinding to List](https://stackoverflow.com/a/33625054/3110834). To see added and removed items immediately in the control, you need to implement `BindingList`. To see property changes immediately, the object should implement `INotifyPropertyChanged`. – Reza Aghaei Jan 12 '19 at 20:53
  • I tried using BindingList and it works fine. But, I want to do similar thing with an Observable class. – user2288650 Jan 13 '19 at 21:07

1 Answers1

0

INotifyPropertyChanged is used if the value of a property changes. The collection itself does not change, its contents do. This is signaled by another interface: INotifyCollectionChanged.

You don't need a custom collection type for that, to get updates when a collection is updated use ObservableCollection instead.

EDIT: I just realized ObservableCollection is not available by default in Windows Forms, but it looks like you can easily add it.

Marcell Toth
  • 3,433
  • 1
  • 21
  • 36