Подтвердить что ты не робот

Общий класс наблюдаемого словаря для DataBinding/WPF С#

Я пытаюсь создать класс наблюдаемого словаря для WPF DataBinding в С#. Я нашел хороший пример от Энди здесь: Двусторонняя привязка данных с помощью словаря в WPF

В соответствии с этим я попытался изменить код следующим образом:

class ObservableDictionary : ViewModelBase
{
    public ObservableDictionary(Dictionary<TKey, TValue> dictionary)
    {
        _data = dictionary;
    }

    private Dictionary<TKey, TValue> _data;

    public Dictionary<TKey, TValue> Data
    {
        get { return this._data; }
    }

    private KeyValuePair<TKey, TValue>? _selectedKey = null;
    public KeyValuePair<TKey, TValue>? SelectedKey
    {
        get { return _selectedKey; }
        set
        {
            _selectedKey = value;
            RaisePropertyChanged("SelectedKey");
            RaisePropertyChanged("SelectedValue");
        }
    }

    public TValue SelectedValue
    {
        get
        {
            return _data[SelectedKey.Value.Key];
        }
        set
        {
            _data[SelectedKey.Value.Key] = value;
            RaisePropertyChanged("SelectedValue");
        }
    }
}

}

К сожалению, я до сих пор не знаю, как передать "общие" словарные объекты.. любые идеи?

Спасибо!

Приветствия

4b9b3361

Ответ 1

Если вы действительно хотите создать ObservableDictionary, я бы предложил создать класс, который реализует как IDictionary, так и INotifyCollectionChanged. Вы всегда можете использовать Dictionary внутри, чтобы реализовать методы IDictionary, чтобы вам не пришлось переопределять это самостоятельно.

Поскольку у вас есть полное представление о том, когда изменяется внутренний Dictionary, вы можете использовать это знание для реализации INotifyCollectionChanged.

Ответ 3

Для исторических целей и для размещения людей по "текущему" пути... Важно знать, что Microsoft теперь разрешает это требование в своем шаблоне "Основная страница" в Windows Store в Visual Studio 2012. Чтобы поддерживать LayoutAwarePage, они сгенерируйте частный класс ObservableDictionary.

Однако они реализуют новый интерфейс IObservableMap, а не IDictionary. Этот интерфейс добавляет событие MapChanged и MapChangedEventHandler, определенное в пространстве имен Windows.Foundation.Collections.

Ниже приведен ниже фрагмент класса ObservableDictionary из LayoutAwarePage.cs, сгенерированного в общей папке вашего проекта:

    /// <summary>
    /// Implementation of IObservableMap that supports reentrancy for use as a default view
    /// model.
    /// </summary>
    private class ObservableDictionary<K, V> : IObservableMap<K, V>
    {
        private class ObservableDictionaryChangedEventArgs : IMapChangedEventArgs<K>
        {
            public ObservableDictionaryChangedEventArgs(CollectionChange change, K key)
            {
                CollectionChange = change;
                Key = key;
            }

            public CollectionChange CollectionChange { get; private set; }
            public K Key { get; private set; }
        }

        private Dictionary<K, V> _dictionary = new Dictionary<K, V>();
        public event MapChangedEventHandler<K, V> MapChanged;

        private void InvokeMapChanged(CollectionChange change, K key)
        {
            var eventHandler = MapChanged;
            if (eventHandler != null)
            {
                eventHandler(this, new ObservableDictionaryChangedEventArgs(change, key));
            }
        }

        public void Add(K key, V value)
        {
            _dictionary.Add(key, value);
            InvokeMapChanged(CollectionChange.ItemInserted, key);
        }

        public void Add(KeyValuePair<K, V> item)
        {
            Add(item.Key, item.Value);
        }

        public bool Remove(K key)
        {
            if (_dictionary.Remove(key))
            {
                InvokeMapChanged(CollectionChange.ItemRemoved, key);
                return true;
            }
            return false;
        }

        public bool Remove(KeyValuePair<K, V> item)
        {
            V currentValue;
            if (_dictionary.TryGetValue(item.Key, out currentValue) &&
                Object.Equals(item.Value, currentValue) && _dictionary.Remove(item.Key))
            {
                InvokeMapChanged(CollectionChange.ItemRemoved, item.Key);
                return true;
            }
            return false;
        }

        public V this[K key]
        {
            get
            {
                return _dictionary[key];
            }
            set
            {
                _dictionary[key] = value;
                InvokeMapChanged(CollectionChange.ItemChanged, key);
            }
        }

        public void Clear()
        {
            var priorKeys = _dictionary.Keys.ToArray();
            _dictionary.Clear();
            foreach (var key in priorKeys)
            {
                InvokeMapChanged(CollectionChange.ItemRemoved, key);
            }
        }

        public ICollection<K> Keys
        {
            get { return _dictionary.Keys; }
        }

        public bool ContainsKey(K key)
        {
            return _dictionary.ContainsKey(key);
        }

        public bool TryGetValue(K key, out V value)
        {
            return _dictionary.TryGetValue(key, out value);
        }

        public ICollection<V> Values
        {
            get { return _dictionary.Values; }
        }

        public bool Contains(KeyValuePair<K, V> item)
        {
            return _dictionary.Contains(item);
        }

        public int Count
        {
            get { return _dictionary.Count; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
        {
            return _dictionary.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _dictionary.GetEnumerator();
        }

        public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex)
        {
            if (array == null) throw new ArgumentNullException("array");
            int arraySize = array.Length;
            foreach (var pair in _dictionary)
            {
                if (arrayIndex >= arraySize) break;
                array[arrayIndex++] = pair;
            }
        }
    }

Дальнейшая проверка нового пространства имен Windows.Foundation.Collections показывает загрузку новых интерфейсов, но только один класс PropertySet. На самом деле это похоже на довольно хороший ObservableDictionary. Но должна быть причина, почему MS все еще генерирует частный ObservableDictionary. Поэтому для выявления плюсов и минусов требуется дополнительная экспертиза.

Короче говоря, либо PropertySet, либо ваш собственный ObservableDictionary на основе IObservableMap должны решить неотложные требования для "текущих" проектов Windows 8 и Phone 8. Однако для старых фреймворков (WPF 4 и Phone 7.5) еще предстоит сделать больше.

Ответ 5

Вы не можете написать что-то, что сделает кого-то еще Словарь, не говоря уже о IDictionary, наблюдаемым без использования какой-либо формы отражения. Проблема заключается в том, что Словарь может быть подклассом с дополнительными мутаторами (например, Sort, или Filter, или что-то еще), которые не вызывают Add and Remove и не обходят ваши события в результате.

Я считаю, что существуют рамки генерации кода, которые позволяют вам делать такие вещи, но я не знаком с ними.