11

I have used an ObservableCollection with WPF for binding and this works well. What I really want at the moment is a Dictionary like one, that has a key that I can use, so effectively like "ObservableCollection".

Can you suggest the code that could be used to provide such an ObservableCollection? The goal is to have a Dictionary like structure that I can bind to from WPF.

Thanks

Greg
  • 34,042
  • 79
  • 253
  • 454

5 Answers5

6

Someone already made it. I haven't try it yet but nothing to lose.

Gabe
  • 84,912
  • 12
  • 139
  • 238
ktutnik
  • 6,882
  • 1
  • 29
  • 34
3

How about:

var collection = new ObservableCollection<KeyValuePair<TKey, TValue>>();

You should be able to address it with:

collection.First(x => x.Key == *your key value*) .Key or .Value

Stevy
  • 3,228
  • 7
  • 22
  • 38
Hitchen
  • 31
  • 1
  • This works in practicality but not in efficiency. A linear search is happening here whereas an actual dictionary implementation would be a simple lookup (constant time on average). – UndergroundCoding Apr 08 '22 at 20:41
  • Doesn't work like a dictionary. You cannot change the value of a keyvaluepair. – JHBonarius Feb 01 '23 at 11:22
1

What about something like :

ObservableCollection<Tuple<string, object>>()

where string and object and sample types of course

eka808
  • 2,257
  • 3
  • 29
  • 41
  • 1
    Depending on the usage, that may work. However, consider how you would 'find' an element by key when using tuples like this. A Dictionary can look up a value by key using hashing and can be quite a bit faster than searching a list for a matching key. – MPavlak Aug 10 '16 at 13:54
  • You made a point. However using an observable collection for huge datasets is probably not a good idea. – eka808 Aug 16 '16 at 00:17
1

Create a class that implements the IDictionary, INotifyCollectionChanged & INotifyPropertyChanged interfaces. The class would have an instance of Dictionary that it would use for the implementation of IDictionary (one of the Add methods is coded below as an example). Both INotifyCollectionChanged and INotifyProperyChanged require the presence of events, these events should be fired at appropriate points in the wrapper functions (again, consult the Add method below for an example)

class ObservableDictionary<TKey, TValue> : IDictionary, INotifyCollectionChanged, INotifyPropertyChanged
{
    private Dictionary<TKey, TValue> mDictionary;
    // Methods & Properties for IDictionary implementation would defer to mDictionary:
    public void Add(TKey key, TValue value){
        mDictionary.Add(key, value);
        OnCollectionChanged(NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value)
        return;
    }
    // Implementation of INotifyCollectionChanged:
    public event NotifyCollectionChangedEventHandler CollectionChanged;
    protected void OnCollectionChanged(NotifyCollectionChangedEventArgs args){
        // event fire implementation
    }
    // Implementation of INotifyProperyChanged:
    public event ProperyChangedEventHandler ProperyChanged;
    protected void OnPropertyChanged(PropertyChangedEventArgs args){
        // event fire implementation
    }
}

Edit:

Note that an implementation of the IDictionary interface directly or indirectly would require that three additional interfaces be implemented:

ICollection<KeyValuePair<TKey,TValue>>
IEnumerable<KeyValuePair<TKey,TValue>>
IEnumerable.

Depending on your needs you may not have to implement the entire IDictionary interface, if you are only going to be calling a couple of the methods then just implement those methods and the IDictionary interface becomes a luxury. You must implement the INotifyCollectionChanged and INotifyPropertyChanged interfaces for binding to work however.Blockquote

Steve Ellinger
  • 3,957
  • 21
  • 19
  • putting this into VS I note there are many more interface methods that would need implementing - is this correct? – Greg Sep 29 '10 at 02:58
  • Yes, if your requirements require you to implement the entire IDictionary interface, see my edits – Steve Ellinger Sep 29 '10 at 03:28
1
public class ObservableDictonary<TKey, TValue> : Dictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged
{
    public event NotifyCollectionChangedEventHandler CollectionChanged;

    public event PropertyChangedEventHandler PropertyChanged;

    public new void Add(TKey key, TValue value)
    {
        base.Add(key, value);
        if (!TryGetValue(key, out _)) return;
        var index = Keys.Count;
        OnPropertyChanged(nameof(Count));
        OnPropertyChanged(nameof(Values));
        OnCollectionChanged(NotifyCollectionChangedAction.Add, value, index);
    }

    public new void Remove(TKey key)
    {
        if (!TryGetValue(key, out var value)) return;
        var index = IndexOf(Keys, key);
        OnPropertyChanged(nameof(Count));
        OnPropertyChanged(nameof(Values));
        OnCollectionChanged(NotifyCollectionChangedAction.Remove, value, index);
        base.Remove(key);
    }

    public new void Clear()
    {

    }

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        PropertyChanged?.Invoke(this, e);
    }

    protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        CollectionChanged?.Invoke(this, e);
    }

    private void OnPropertyChanged(string propertyName)
    {
        OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    private void OnCollectionChanged(NotifyCollectionChangedAction action, object item)
    {
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item));
    }

    private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index)
    {
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index));
    }

    private int IndexOf(KeyCollection keys, TKey key)
    {
        var index = 0;
        foreach (var k in keys)
        {
            if (Equals(k, key))
                return index;
            index++;
        }
        return -1;
    }
}

I override Add, Remove and Clear. You must understand, if you use extension method or simple method, which take Dictionary parameter, you will not see changing, because in this situation, Add or Remove method will use of Dictionary (not ObservableDictonary). So you must direct methods (Add or Remove) of ObservableDictonary

hirse
  • 2,394
  • 1
  • 22
  • 24
Smagin Alexey
  • 305
  • 2
  • 6