WPF - How can I implement an ObservableCollection<K,T> with a key (like a Dictionary)?

邮差的信 提交于 2019-12-21 04:22:14

问题


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


回答1:


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




回答2:


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




回答3:


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




回答4:


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




回答5:


What about something like :

ObservableCollection<Tuple<string, object>>()

where string and object and sample types of course



来源:https://stackoverflow.com/questions/3818365/wpf-how-can-i-implement-an-observablecollectionk-t-with-a-key-like-a-dictio

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!