Freezed
This commit is contained in:
parent
327850a0db
commit
c7cf88a57d
57
src/ObservableCollections/FreezedDictionary.cs
Normal file
57
src/ObservableCollections/FreezedDictionary.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using ObservableCollections.Internal;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ObservableCollections
|
||||
{
|
||||
public sealed class FreezedDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>, IFreezedCollection<KeyValuePair<TKey, TValue>>
|
||||
where TKey : notnull
|
||||
{
|
||||
readonly IReadOnlyDictionary<TKey, TValue> dictionary;
|
||||
|
||||
public FreezedDictionary(IReadOnlyDictionary<TKey, TValue> dictionary)
|
||||
{
|
||||
this.dictionary = dictionary;
|
||||
}
|
||||
|
||||
public TValue this[TKey key] => dictionary[key];
|
||||
|
||||
public IEnumerable<TKey> Keys => dictionary.Keys;
|
||||
|
||||
public IEnumerable<TValue> Values => dictionary.Values;
|
||||
|
||||
public int Count => dictionary.Count;
|
||||
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
return dictionary.ContainsKey(key);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||
{
|
||||
return dictionary.GetEnumerator();
|
||||
}
|
||||
|
||||
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
|
||||
{
|
||||
return dictionary.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable)dictionary).GetEnumerator();
|
||||
}
|
||||
|
||||
public ISynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform, bool reverse = false)
|
||||
{
|
||||
return new FreezedView<KeyValuePair<TKey, TValue>, TView>(dictionary, transform, reverse);
|
||||
}
|
||||
|
||||
public ISortableSynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateSortableView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform)
|
||||
{
|
||||
return new FreezedSortableView<KeyValuePair<TKey, TValue>, TView>(dictionary, transform);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
|
||||
namespace ObservableCollections
|
||||
@ -36,12 +35,12 @@ namespace ObservableCollections
|
||||
|
||||
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false)
|
||||
{
|
||||
return new View<TView>(this, transform, reverse);
|
||||
return new FreezedView<T, TView>(list, transform, reverse);
|
||||
}
|
||||
|
||||
public ISortableSynchronizedView<T, TView> CreateSortableView<TView>(Func<T, TView> transform)
|
||||
{
|
||||
return new SortableView<TView>(this, transform);
|
||||
return new FreezedSortableView<T, TView>(list, transform);
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
@ -58,200 +57,5 @@ namespace ObservableCollections
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
class View<TView> : ISynchronizedView<T, TView>
|
||||
{
|
||||
readonly bool reverse;
|
||||
readonly List<(T, TView)> list;
|
||||
|
||||
ISynchronizedViewFilter<T, TView> filter;
|
||||
|
||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
||||
|
||||
public object SyncRoot { get; } = new object();
|
||||
|
||||
public View(FreezedList<T> source, Func<T, TView> selector, bool reverse)
|
||||
{
|
||||
this.reverse = reverse;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
this.list = source.Select(x => (x, selector(x))).ToList();
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return list.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = filter;
|
||||
foreach (var (value, view) in list)
|
||||
{
|
||||
filter.Invoke(value, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetFilter(Action<T, TView>? resetAction)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var (item, view) in list)
|
||||
{
|
||||
resetAction(item, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
if (!reverse)
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.GetEnumerator(), filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.AsEnumerable().Reverse().GetEnumerator(), filter);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
||||
{
|
||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
||||
}
|
||||
}
|
||||
|
||||
class SortableView<TView> : ISortableSynchronizedView<T, TView>
|
||||
{
|
||||
readonly (T, TView)[] array;
|
||||
|
||||
ISynchronizedViewFilter<T, TView> filter;
|
||||
|
||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
||||
|
||||
public object SyncRoot { get; } = new object();
|
||||
|
||||
public SortableView(FreezedList<T> source, Func<T, TView> selector)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
this.array = source.Select(x => (x, selector(x))).ToArray();
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return array.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = filter;
|
||||
foreach (var (value, view) in array)
|
||||
{
|
||||
filter.Invoke(value, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetFilter(Action<T, TView>? resetAction)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var (item, view) in array)
|
||||
{
|
||||
resetAction(item, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, array.AsEnumerable().GetEnumerator(), filter);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Sort(IComparer<T> comparer)
|
||||
{
|
||||
Array.Sort(array, new TComparer(comparer));
|
||||
}
|
||||
|
||||
public void Sort(IComparer<TView> viewComparer)
|
||||
{
|
||||
Array.Sort(array, new TViewComparer(viewComparer));
|
||||
}
|
||||
|
||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
||||
{
|
||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
||||
}
|
||||
|
||||
class TComparer : IComparer<(T, TView)>
|
||||
{
|
||||
readonly IComparer<T> comparer;
|
||||
|
||||
public TComparer(IComparer<T> comparer)
|
||||
{
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public int Compare((T, TView) x, (T, TView) y)
|
||||
{
|
||||
return comparer.Compare(x.Item1, y.Item1);
|
||||
}
|
||||
}
|
||||
|
||||
class TViewComparer : IComparer<(T, TView)>
|
||||
{
|
||||
readonly IComparer<TView> comparer;
|
||||
|
||||
public TViewComparer(IComparer<TView> comparer)
|
||||
{
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public int Compare((T, TView) x, (T, TView) y)
|
||||
{
|
||||
return comparer.Compare(x.Item2, y.Item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
203
src/ObservableCollections/Internal/FreezedView.cs
Normal file
203
src/ObservableCollections/Internal/FreezedView.cs
Normal file
@ -0,0 +1,203 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
|
||||
namespace ObservableCollections.Internal
|
||||
{
|
||||
internal sealed class FreezedView<T, TView> : ISynchronizedView<T, TView>
|
||||
{
|
||||
readonly bool reverse;
|
||||
readonly List<(T, TView)> list;
|
||||
|
||||
ISynchronizedViewFilter<T, TView> filter;
|
||||
|
||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
||||
|
||||
public object SyncRoot { get; } = new object();
|
||||
|
||||
public FreezedView(IEnumerable<T> source, Func<T, TView> selector, bool reverse)
|
||||
{
|
||||
this.reverse = reverse;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
this.list = source.Select(x => (x, selector(x))).ToList();
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return list.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = filter;
|
||||
foreach (var (value, view) in list)
|
||||
{
|
||||
filter.Invoke(value, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetFilter(Action<T, TView>? resetAction)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var (item, view) in list)
|
||||
{
|
||||
resetAction(item, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
if (!reverse)
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.GetEnumerator(), filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, list.AsEnumerable().Reverse().GetEnumerator(), filter);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
||||
{
|
||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class FreezedSortableView<T, TView> : ISortableSynchronizedView<T, TView>
|
||||
{
|
||||
readonly (T, TView)[] array;
|
||||
|
||||
ISynchronizedViewFilter<T, TView> filter;
|
||||
|
||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
||||
|
||||
public object SyncRoot { get; } = new object();
|
||||
|
||||
public FreezedSortableView(IEnumerable<T> source, Func<T, TView> selector)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
this.array = source.Select(x => (x, selector(x))).ToArray();
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return array.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = filter;
|
||||
foreach (var (value, view) in array)
|
||||
{
|
||||
filter.Invoke(value, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetFilter(Action<T, TView>? resetAction)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var (item, view) in array)
|
||||
{
|
||||
resetAction(item, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<(T, TView)> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedViewEnumerator<T, TView>(SyncRoot, array.AsEnumerable().GetEnumerator(), filter);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Sort(IComparer<T> comparer)
|
||||
{
|
||||
Array.Sort(array, new TComparer(comparer));
|
||||
}
|
||||
|
||||
public void Sort(IComparer<TView> viewComparer)
|
||||
{
|
||||
Array.Sort(array, new TViewComparer(viewComparer));
|
||||
}
|
||||
|
||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
||||
{
|
||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
||||
}
|
||||
|
||||
class TComparer : IComparer<(T, TView)>
|
||||
{
|
||||
readonly IComparer<T> comparer;
|
||||
|
||||
public TComparer(IComparer<T> comparer)
|
||||
{
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public int Compare((T, TView) x, (T, TView) y)
|
||||
{
|
||||
return comparer.Compare(x.Item1, y.Item1);
|
||||
}
|
||||
}
|
||||
|
||||
class TViewComparer : IComparer<(T, TView)>
|
||||
{
|
||||
readonly IComparer<TView> comparer;
|
||||
|
||||
public TViewComparer(IComparer<TView> comparer)
|
||||
{
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public int Compare((T, TView) x, (T, TView) y)
|
||||
{
|
||||
return comparer.Compare(x.Item2, y.Item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,27 +4,25 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ObservableCollections
|
||||
{
|
||||
public sealed partial class ObservableDictionary<TKey, TValue>
|
||||
{
|
||||
public ISynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform, bool reverse = false)
|
||||
public ISynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform, bool _ = false)
|
||||
{
|
||||
// reverse is no used.
|
||||
throw new NotImplementedException();
|
||||
return new View<TView>(this, transform);
|
||||
}
|
||||
|
||||
public ISynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateSortedView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform, IComparer<KeyValuePair<TKey, TValue>> comparer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return new SortedView<TView>(this, transform, comparer);
|
||||
}
|
||||
|
||||
public ISynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateSortedView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform, IComparer<TView> viewComparer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return new ViewComparerSortedView<TView>(this, transform, viewComparer);
|
||||
}
|
||||
|
||||
class View<TView> : ISynchronizedView<KeyValuePair<TKey, TValue>, TView>
|
||||
@ -293,5 +291,152 @@ namespace ObservableCollections
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint.
|
||||
|
||||
class ViewComparerSortedView<TView> : ISynchronizedView<KeyValuePair<TKey, TValue>, TView>
|
||||
{
|
||||
readonly ObservableDictionary<TKey, TValue> source;
|
||||
readonly Func<KeyValuePair<TKey, TValue>, TView> selector;
|
||||
readonly Dictionary<TKey, TView> viewMap;
|
||||
readonly SortedDictionary<TView, KeyValuePair<TKey, TValue>> dict;
|
||||
ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> filter;
|
||||
|
||||
public ViewComparerSortedView(ObservableDictionary<TKey, TValue> source, Func<KeyValuePair<TKey, TValue>, TView> selector, IComparer<TView> viewComparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector = selector;
|
||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.AlwaysTrue;
|
||||
this.SyncRoot = new object();
|
||||
lock (source.SyncRoot)
|
||||
{
|
||||
this.viewMap = new Dictionary<TKey, TView>(source.Count);
|
||||
this.dict = new SortedDictionary<TView, KeyValuePair<TKey, TValue>>(viewComparer);
|
||||
foreach (var item in source.dictionary)
|
||||
{
|
||||
var v = selector(item);
|
||||
dict.Add(v, item);
|
||||
viewMap.Add(item.Key, v);
|
||||
}
|
||||
this.source.CollectionChanged += SourceCollectionChanged;
|
||||
}
|
||||
}
|
||||
|
||||
public object SyncRoot { get; }
|
||||
public event NotifyCollectionChangedEventHandler<KeyValuePair<TKey, TValue>>? RoutingCollectionChanged;
|
||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return dict.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.source.CollectionChanged -= SourceCollectionChanged;
|
||||
}
|
||||
|
||||
public void AttachFilter(ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> filter)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = filter;
|
||||
foreach (var v in dict)
|
||||
{
|
||||
filter.Invoke(v.Value, v.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetFilter(Action<KeyValuePair<TKey, TValue>, TView>? resetAction)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.AlwaysTrue;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var v in dict)
|
||||
{
|
||||
resetAction(v.Value, v.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public INotifyCollectionChangedSynchronizedView<KeyValuePair<TKey, TValue>, TView> WithINotifyCollectionChanged()
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return new NotifyCollectionChangedSynchronizedView<KeyValuePair<TKey, TValue>, TView>(this);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<(KeyValuePair<TKey, TValue>, TView)> GetEnumerator()
|
||||
{
|
||||
return new SynchronizedViewEnumerator<KeyValuePair<TKey, TValue>, TView>(SyncRoot,
|
||||
dict.Select(x => (x.Value, x.Key)).GetEnumerator(),
|
||||
filter);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>> e)
|
||||
{
|
||||
// ObservableDictionary only provides single item operation and does not use int index.
|
||||
lock (SyncRoot)
|
||||
{
|
||||
switch (e.Action)
|
||||
{
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
{
|
||||
var v = selector(e.NewItem);
|
||||
var k = new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value);
|
||||
dict.Add(v, k);
|
||||
viewMap.Add(e.NewItem.Key, v);
|
||||
filter.Invoke(k, v);
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
{
|
||||
if (viewMap.Remove(e.OldItem.Key, out var view))
|
||||
{
|
||||
dict.Remove(view);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Move:
|
||||
case NotifyCollectionChangedAction.Replace:
|
||||
{
|
||||
if (viewMap.Remove(e.OldItem.Key, out var view))
|
||||
{
|
||||
dict.Remove(view);
|
||||
}
|
||||
goto case NotifyCollectionChangedAction.Add;
|
||||
}
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
{
|
||||
dict.Clear();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
RoutingCollectionChanged?.Invoke(e);
|
||||
CollectionStateChanged?.Invoke(e.Action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore CS8714
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user