WPF - Как я могу реализовать ObservableCollection <K, T> с ключом (например, словарь)? - PullRequest
8 голосов
/ 29 сентября 2010

Я использовал ObservableCollection с WPF для привязки, и это хорошо работает.В настоящий момент мне действительно нужен словарь, подобный тому, который имеет ключ, который я могу использовать, например, «ObservableCollection».

Можете ли вы предложить код, который можно использовать для обеспечения такой ObservableCollection?Цель состоит в том, чтобы создать словарную структуру, которую я могу связать с WPF.

Спасибо

Ответы [ 4 ]

5 голосов
/ 29 сентября 2010

Кто-то уже сделал это . Я еще не пробовал, но терять нечего.

1 голос
/ 26 февраля 2018
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;
    }
}

Я переопределяю Добавить, Удалить и Очистить.Вы должны понимать, что если вы используете метод расширения или простой метод, который принимает параметр Dictionary, вы не увидите изменений, потому что в этой ситуации метод Add или Remove будет использовать Dictionary (не ObservableDictonary).Таким образом, вы должны направить методы (Добавить или Удалить) ObservableDictonary

1 голос
/ 29 сентября 2010

Создайте класс, который реализует интерфейсы IDictionary, INotifyCollectionChanged и INotifyPropertyChanged. У класса будет экземпляр Dictionary, который он будет использовать для реализации IDictionary (один из методов Add кодируется ниже в качестве примера). И INotifyCollectionChanged, и INotifyProperyChanged требуют наличия событий, эти события должны запускаться в соответствующих точках в функциях-оболочках (опять же, обратитесь к методу Add ниже для примера)

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:

Обратите внимание, что реализация интерфейса IDictionary прямо или косвенно потребует реализации трех дополнительных интерфейсов:

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

В зависимости от ваших потребностей, вам может не понадобиться реализовывать весь интерфейс IDictionary, если вы собираетесь вызывать только пару методов, а затем просто реализовать эти методы, и интерфейс IDictionary станет роскошью. Однако для привязки к работе необходимо реализовать интерфейсы INotifyCollectionChanged и INotifyPropertyChanged. Цитата

0 голосов
/ 04 марта 2015

Как насчет чего-то вроде:

ObservableCollection<Tuple<string, object>>()

где строка, тип объекта и примеры курса

...