From f377d044d6f0c321a01789f55d4a024bfdb8129e Mon Sep 17 00:00:00 2001 From: John Gross Date: Thu, 21 Sep 2017 20:15:18 -0700 Subject: [PATCH] Observable type improvements --- Torch/Collections/ObservableDictionary.cs | 147 +++++++++++++++++++--- Torch/ViewModels/ViewModel.cs | 11 ++ 2 files changed, 142 insertions(+), 16 deletions(-) diff --git a/Torch/Collections/ObservableDictionary.cs b/Torch/Collections/ObservableDictionary.cs index 2d3f955..68a4a33 100644 --- a/Torch/Collections/ObservableDictionary.cs +++ b/Torch/Collections/ObservableDictionary.cs @@ -1,8 +1,10 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Windows.Threading; @@ -10,28 +12,148 @@ using System.Windows.Threading; namespace Torch.Collections { [Serializable] - public class ObservableDictionary : Dictionary, INotifyCollectionChanged, INotifyPropertyChanged + public class ObservableDictionary : ViewModel, IDictionary, INotifyCollectionChanged { - /// - public new void Add(TKey key, TValue value) + private IDictionary _internalDict; + + public ObservableDictionary() { - base.Add(key, value); - var kv = new KeyValuePair(key, value); - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, kv)); + _internalDict = new Dictionary(); + } + + public ObservableDictionary(IDictionary dictionary) + { + _internalDict = new Dictionary(dictionary); + } + + /// + /// Create a using the given dictionary by reference. The original dictionary should not be used after calling this. + /// + public static ObservableDictionary ByReference(IDictionary dictionary) + { + return new ObservableDictionary + { + _internalDict = dictionary + }; } /// - public new bool Remove(TKey key) + public event NotifyCollectionChangedEventHandler CollectionChanged; + + /// + public event PropertyChangedEventHandler PropertyChanged; + + /// + public IEnumerator> GetEnumerator() { - if (!ContainsKey(key)) + return _internalDict.GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)_internalDict).GetEnumerator(); + } + + /// + public void Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + /// + public bool Remove(KeyValuePair item) + { + return Remove(item.Key); + } + + /// + public void Clear() + { + _internalDict.Clear(); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + OnPropertyChanged(nameof(Count)); + } + + /// + public bool Contains(KeyValuePair item) + { + return _internalDict.Contains(item); + } + + /// + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + foreach (var kv in _internalDict) + { + array[arrayIndex] = kv; + arrayIndex++; + } + } + + /// + public int Count => _internalDict.Count; + + /// + public bool IsReadOnly => false; + + /// + public bool ContainsKey(TKey key) + { + return _internalDict.ContainsKey(key); + } + + /// + public void Add(TKey key, TValue value) + { + _internalDict.Add(key, value); + var kv = new KeyValuePair(key, value); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, kv)); + OnPropertyChanged(nameof(Count)); + } + + /// + public bool Remove(TKey key) + { + if (!_internalDict.ContainsKey(key)) return false; var kv = new KeyValuePair(key, this[key]); - base.Remove(key); + if (!_internalDict.Remove(key)) + return false; + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, kv)); + OnPropertyChanged(nameof(Count)); return true; } + /// + public bool TryGetValue(TKey key, out TValue value) + { + return _internalDict.TryGetValue(key, out value); + } + + /// + public TValue this[TKey key] + { + get => _internalDict[key]; + set + { + var oldKv = new KeyValuePair(key, _internalDict[key]); + var newKv = new KeyValuePair(key, value); + _internalDict[key] = value; + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newKv, oldKv)); + } + + + } + + /// + public ICollection Keys => _internalDict.Keys; + + /// + public ICollection Values => _internalDict.Values; + private void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { NotifyCollectionChangedEventHandler collectionChanged = CollectionChanged; @@ -52,12 +174,5 @@ namespace Torch.Collections nh.Invoke(this, e); } } - - - /// - public event NotifyCollectionChangedEventHandler CollectionChanged; - - /// - public event PropertyChangedEventHandler PropertyChanged; } } diff --git a/Torch/ViewModels/ViewModel.cs b/Torch/ViewModels/ViewModel.cs index 010f34c..7233102 100644 --- a/Torch/ViewModels/ViewModel.cs +++ b/Torch/ViewModels/ViewModel.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; @@ -20,6 +21,16 @@ namespace Torch PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); } + protected virtual void SetValue(ref T backingField, T value, [CallerMemberName] string propName = "") + { + if (backingField.Equals(value)) + return; + + backingField = value; + // ReSharper disable once ExplicitCallerInfoArgument + OnPropertyChanged(propName); + } + /// /// Fires PropertyChanged for all properties. ///