Observable type improvements

This commit is contained in:
John Gross
2017-09-21 20:15:18 -07:00
parent 44ebcc5d25
commit f377d044d6
2 changed files with 142 additions and 16 deletions

View File

@@ -1,8 +1,10 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Threading; using System.Windows.Threading;
@@ -10,28 +12,148 @@ using System.Windows.Threading;
namespace Torch.Collections namespace Torch.Collections
{ {
[Serializable] [Serializable]
public class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged public class ObservableDictionary<TKey, TValue> : ViewModel, IDictionary<TKey, TValue>, INotifyCollectionChanged
{ {
/// <inheritdoc /> private IDictionary<TKey, TValue> _internalDict;
public new void Add(TKey key, TValue value)
public ObservableDictionary()
{ {
base.Add(key, value); _internalDict = new Dictionary<TKey, TValue>();
var kv = new KeyValuePair<TKey, TValue>(key, value); }
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, kv));
public ObservableDictionary(IDictionary<TKey, TValue> dictionary)
{
_internalDict = new Dictionary<TKey, TValue>(dictionary);
}
/// <summary>
/// Create a <see cref="ObservableDictionary{TKey,TValue}"/> using the given dictionary by reference. The original dictionary should not be used after calling this.
/// </summary>
public static ObservableDictionary<TKey, TValue> ByReference(IDictionary<TKey, TValue> dictionary)
{
return new ObservableDictionary<TKey, TValue>
{
_internalDict = dictionary
};
} }
/// <inheritdoc /> /// <inheritdoc />
public new bool Remove(TKey key) public event NotifyCollectionChangedEventHandler CollectionChanged;
/// <inheritdoc />
public event PropertyChangedEventHandler PropertyChanged;
/// <inheritdoc />
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{ {
if (!ContainsKey(key)) return _internalDict.GetEnumerator();
}
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_internalDict).GetEnumerator();
}
/// <inheritdoc />
public void Add(KeyValuePair<TKey, TValue> item)
{
Add(item.Key, item.Value);
}
/// <inheritdoc />
public bool Remove(KeyValuePair<TKey, TValue> item)
{
return Remove(item.Key);
}
/// <inheritdoc />
public void Clear()
{
_internalDict.Clear();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
OnPropertyChanged(nameof(Count));
}
/// <inheritdoc />
public bool Contains(KeyValuePair<TKey, TValue> item)
{
return _internalDict.Contains(item);
}
/// <inheritdoc />
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
foreach (var kv in _internalDict)
{
array[arrayIndex] = kv;
arrayIndex++;
}
}
/// <inheritdoc />
public int Count => _internalDict.Count;
/// <inheritdoc />
public bool IsReadOnly => false;
/// <inheritdoc />
public bool ContainsKey(TKey key)
{
return _internalDict.ContainsKey(key);
}
/// <inheritdoc />
public void Add(TKey key, TValue value)
{
_internalDict.Add(key, value);
var kv = new KeyValuePair<TKey, TValue>(key, value);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, kv));
OnPropertyChanged(nameof(Count));
}
/// <inheritdoc />
public bool Remove(TKey key)
{
if (!_internalDict.ContainsKey(key))
return false; return false;
var kv = new KeyValuePair<TKey, TValue>(key, this[key]); var kv = new KeyValuePair<TKey, TValue>(key, this[key]);
base.Remove(key); if (!_internalDict.Remove(key))
return false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, kv)); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, kv));
OnPropertyChanged(nameof(Count));
return true; return true;
} }
/// <inheritdoc />
public bool TryGetValue(TKey key, out TValue value)
{
return _internalDict.TryGetValue(key, out value);
}
/// <inheritdoc />
public TValue this[TKey key]
{
get => _internalDict[key];
set
{
var oldKv = new KeyValuePair<TKey, TValue>(key, _internalDict[key]);
var newKv = new KeyValuePair<TKey, TValue>(key, value);
_internalDict[key] = value;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newKv, oldKv));
}
}
/// <inheritdoc />
public ICollection<TKey> Keys => _internalDict.Keys;
/// <inheritdoc />
public ICollection<TValue> Values => _internalDict.Values;
private void OnCollectionChanged(NotifyCollectionChangedEventArgs e) private void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{ {
NotifyCollectionChangedEventHandler collectionChanged = CollectionChanged; NotifyCollectionChangedEventHandler collectionChanged = CollectionChanged;
@@ -52,12 +174,5 @@ namespace Torch.Collections
nh.Invoke(this, e); nh.Invoke(this, e);
} }
} }
/// <inheritdoc />
public event NotifyCollectionChangedEventHandler CollectionChanged;
/// <inheritdoc />
public event PropertyChangedEventHandler PropertyChanged;
} }
} }

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -20,6 +21,16 @@ namespace Torch
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
} }
protected virtual void SetValue<T>(ref T backingField, T value, [CallerMemberName] string propName = "")
{
if (backingField.Equals(value))
return;
backingField = value;
// ReSharper disable once ExplicitCallerInfoArgument
OnPropertyChanged(propName);
}
/// <summary> /// <summary>
/// Fires PropertyChanged for all properties. /// Fires PropertyChanged for all properties.
/// </summary> /// </summary>