Refactor property changed implementations
This commit is contained in:
@@ -12,7 +12,7 @@ using System.Windows.Threading;
|
|||||||
namespace Torch.Collections
|
namespace Torch.Collections
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ObservableDictionary<TKey, TValue> : ViewModel, IDictionary<TKey, TValue>, INotifyCollectionChanged
|
public class ObservableDictionary<TKey, TValue> : ViewModel, IDictionary<TKey, TValue>
|
||||||
{
|
{
|
||||||
private IDictionary<TKey, TValue> _internalDict;
|
private IDictionary<TKey, TValue> _internalDict;
|
||||||
|
|
||||||
@@ -37,12 +37,6 @@ namespace Torch.Collections
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||||
{
|
{
|
||||||
@@ -153,26 +147,5 @@ namespace Torch.Collections
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ICollection<TValue> Values => _internalDict.Values;
|
public ICollection<TValue> Values => _internalDict.Values;
|
||||||
|
|
||||||
private void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
NotifyCollectionChangedEventHandler collectionChanged = CollectionChanged;
|
|
||||||
if (collectionChanged != null)
|
|
||||||
foreach (NotifyCollectionChangedEventHandler nh in collectionChanged.GetInvocationList())
|
|
||||||
{
|
|
||||||
var dispObj = nh.Target as DispatcherObject;
|
|
||||||
|
|
||||||
var dispatcher = dispObj?.Dispatcher;
|
|
||||||
if (dispatcher != null && !dispatcher.CheckAccess())
|
|
||||||
{
|
|
||||||
dispatcher.BeginInvoke(
|
|
||||||
(Action)(() => nh.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))),
|
|
||||||
DispatcherPriority.DataBind);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
nh.Invoke(this, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,16 +12,10 @@ namespace Torch
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An observable version of <see cref="List{T}"/>.
|
/// An observable version of <see cref="List{T}"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ObservableList<T> : IList<T>, INotifyCollectionChanged, INotifyPropertyChanged
|
public class ObservableList<T> : ViewModel, IList<T>
|
||||||
{
|
{
|
||||||
private List<T> _internalList = new List<T>();
|
private List<T> _internalList = new List<T>();
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
@@ -146,31 +140,6 @@ namespace Torch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
var collectionChanged = CollectionChanged;
|
|
||||||
if (collectionChanged != null)
|
|
||||||
foreach (var del in collectionChanged.GetInvocationList())
|
|
||||||
{
|
|
||||||
var nh = (NotifyCollectionChangedEventHandler)del;
|
|
||||||
var dispObj = nh.Target as DispatcherObject;
|
|
||||||
|
|
||||||
var dispatcher = dispObj?.Dispatcher;
|
|
||||||
if (dispatcher != null && !dispatcher.CheckAccess())
|
|
||||||
{
|
|
||||||
dispatcher.BeginInvoke(() => nh.Invoke(this, e), DispatcherPriority.DataBind);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
nh.Invoke(this, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IEnumerator<T> GetEnumerator()
|
public IEnumerator<T> GetEnumerator()
|
||||||
{
|
{
|
||||||
|
@@ -2,6 +2,9 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
namespace Torch
|
namespace Torch
|
||||||
{
|
{
|
||||||
@@ -37,6 +40,63 @@ namespace Torch
|
|||||||
return source as IReadOnlyDictionary<TKey, TValue> ?? new ReadOnlyDictionary<TKey, TValue>(source);
|
return source as IReadOnlyDictionary<TKey, TValue> ?? new ReadOnlyDictionary<TKey, TValue>(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IReadOnlyDictionary<TKey, TValue> AsReadOnlyObservable<TKey, TValue>(this IDictionary<TKey, TValue> source)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
throw new ArgumentNullException(nameof(source));
|
||||||
|
return new ObservableReadOnlyDictionary<TKey, TValue>(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class ObservableReadOnlyDictionary<TKey, TValue> : ViewModel, IReadOnlyDictionary<TKey, TValue>
|
||||||
|
{
|
||||||
|
private readonly IDictionary<TKey, TValue> _dictionary;
|
||||||
|
|
||||||
|
public ObservableReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
|
||||||
|
{
|
||||||
|
_dictionary = dictionary;
|
||||||
|
|
||||||
|
if (_dictionary is INotifyPropertyChanged p)
|
||||||
|
p.PropertyChanged += OnPropertyChanged;
|
||||||
|
|
||||||
|
if (_dictionary is INotifyCollectionChanged c)
|
||||||
|
c.CollectionChanged += OnCollectionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
OnCollectionChanged(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(e.PropertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => _dictionary.GetEnumerator();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_dictionary).GetEnumerator();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int Count => _dictionary.Count;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool ContainsKey(TKey key) => _dictionary.ContainsKey(key);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool TryGetValue(TKey key, out TValue value) => _dictionary.TryGetValue(key, out value);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public TValue this[TKey key] => _dictionary[key];
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IEnumerable<TKey> Keys => _dictionary.Keys;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IEnumerable<TValue> Values => _dictionary.Values;
|
||||||
|
}
|
||||||
|
|
||||||
sealed class ReadOnlyCollectionAdapter<T> : IReadOnlyCollection<T>
|
sealed class ReadOnlyCollectionAdapter<T> : IReadOnlyCollection<T>
|
||||||
{
|
{
|
||||||
private readonly ICollection<T> _source;
|
private readonly ICollection<T> _source;
|
||||||
|
@@ -7,21 +7,47 @@ 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;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
namespace Torch
|
namespace Torch
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides a method to notify an observer of changes to an object's properties.
|
/// Provides a method to notify an observer of changes to an object's properties.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class ViewModel : INotifyPropertyChanged
|
public abstract class ViewModel : INotifyPropertyChanged, INotifyCollectionChanged
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||||
|
|
||||||
protected virtual void OnPropertyChanged([CallerMemberName] string propName = "")
|
protected virtual void OnPropertyChanged([CallerMemberName] string propName = "")
|
||||||
{
|
{
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
NotifyCollectionChangedEventHandler collectionChanged = CollectionChanged;
|
||||||
|
if (collectionChanged != null)
|
||||||
|
foreach (NotifyCollectionChangedEventHandler nh in collectionChanged.GetInvocationList())
|
||||||
|
{
|
||||||
|
var dispObj = nh.Target as DispatcherObject;
|
||||||
|
|
||||||
|
var dispatcher = dispObj?.Dispatcher;
|
||||||
|
if (dispatcher != null && !dispatcher.CheckAccess())
|
||||||
|
{
|
||||||
|
dispatcher.BeginInvoke(
|
||||||
|
(Action)(() => nh.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))),
|
||||||
|
DispatcherPriority.DataBind);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nh.Invoke(this, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void SetValue<T>(ref T backingField, T value, [CallerMemberName] string propName = "")
|
protected virtual void SetValue<T>(ref T backingField, T value, [CallerMemberName] string propName = "")
|
||||||
{
|
{
|
||||||
if (backingField.Equals(value))
|
if (backingField.Equals(value))
|
||||||
|
Reference in New Issue
Block a user