new filter
This commit is contained in:
parent
c0fb7375e0
commit
59300d8ee8
@ -7,32 +7,42 @@ namespace ObservableCollections
|
||||
bool IsMatch(T value, TView view);
|
||||
void WhenTrue(T value, TView view);
|
||||
void WhenFalse(T value, TView view);
|
||||
void OnCollectionChanged(ChangedKind changedKind, T value, TView view);
|
||||
}
|
||||
|
||||
public enum ChangedKind
|
||||
{
|
||||
Add, Remove
|
||||
}
|
||||
|
||||
public class SynchronizedViewFilter<T, TView> : ISynchronizedViewFilter<T, TView>
|
||||
{
|
||||
public static readonly ISynchronizedViewFilter<T, TView> AlwaysTrue = new TrueViewFilter();
|
||||
public static readonly ISynchronizedViewFilter<T, TView> Null = new NullViewFilter();
|
||||
|
||||
readonly Func<T, TView, bool> isMatch;
|
||||
readonly Action<T, TView>? whenTrue;
|
||||
readonly Action<T, TView>? whenFalse;
|
||||
readonly Action<ChangedKind, T, TView>? onCollectionChanged;
|
||||
|
||||
public SynchronizedViewFilter(Func<T, TView, bool> isMatch, Action<T, TView>? whenTrue, Action<T, TView>? whenFalse)
|
||||
public SynchronizedViewFilter(Func<T, TView, bool> isMatch, Action<T, TView>? whenTrue, Action<T, TView>? whenFalse, Action<ChangedKind, T, TView>? onCollectionChanged)
|
||||
{
|
||||
this.isMatch = isMatch;
|
||||
this.whenTrue = whenTrue;
|
||||
this.whenFalse = whenFalse;
|
||||
this.onCollectionChanged = onCollectionChanged;
|
||||
}
|
||||
|
||||
public bool IsMatch(T value, TView view) => isMatch(value, view);
|
||||
public void WhenFalse(T value, TView view) => whenFalse?.Invoke(value, view);
|
||||
public void WhenTrue(T value, TView view) => whenTrue?.Invoke(value, view);
|
||||
public void OnCollectionChanged(ChangedKind changedKind, T value, TView view) => onCollectionChanged?.Invoke(changedKind, value, view);
|
||||
|
||||
class TrueViewFilter : ISynchronizedViewFilter<T, TView>
|
||||
class NullViewFilter : ISynchronizedViewFilter<T, TView>
|
||||
{
|
||||
public bool IsMatch(T value, TView view) => true;
|
||||
public void WhenFalse(T value, TView view) { }
|
||||
public void WhenTrue(T value, TView view) { }
|
||||
public void OnCollectionChanged(ChangedKind changedKind, T value, TView view) { }
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,20 +50,53 @@ namespace ObservableCollections
|
||||
{
|
||||
public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, TView, bool> filter)
|
||||
{
|
||||
source.AttachFilter(new SynchronizedViewFilter<T, TView>(filter, null, null));
|
||||
source.AttachFilter(new SynchronizedViewFilter<T, TView>(filter, null, null, null));
|
||||
}
|
||||
|
||||
public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, TView, bool> isMatch, Action<T, TView>? whenTrue, Action<T, TView>? whenFalse)
|
||||
{
|
||||
source.AttachFilter(new SynchronizedViewFilter<T, TView>(isMatch, whenTrue, whenFalse));
|
||||
source.AttachFilter(new SynchronizedViewFilter<T, TView>(isMatch, whenTrue, whenFalse, null));
|
||||
}
|
||||
|
||||
public static void Invoke<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T, TView) value)
|
||||
public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, TView, bool> isMatch, Action<T, TView>? whenTrue, Action<T, TView>? whenFalse, Action<ChangedKind, T, TView>? onCollectionChanged)
|
||||
{
|
||||
Invoke(filter, value.Item1, value.Item2);
|
||||
source.AttachFilter(new SynchronizedViewFilter<T, TView>(isMatch, whenTrue, whenFalse, onCollectionChanged));
|
||||
}
|
||||
|
||||
public static void Invoke<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view)
|
||||
public static bool IsNullFilter<T, TView>(this ISynchronizedViewFilter<T, TView> filter)
|
||||
{
|
||||
return filter == SynchronizedViewFilter<T, TView>.Null;
|
||||
}
|
||||
|
||||
internal static void InvokeOnAdd<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value)
|
||||
{
|
||||
InvokeOnAdd(filter, value.value, value.view);
|
||||
}
|
||||
|
||||
internal static void InvokeOnAdd<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view)
|
||||
{
|
||||
if (filter.IsMatch(value, view))
|
||||
{
|
||||
filter.WhenTrue(value, view);
|
||||
}
|
||||
else
|
||||
{
|
||||
filter.WhenFalse(value, view);
|
||||
}
|
||||
filter.OnCollectionChanged(ChangedKind.Add, value, view);
|
||||
}
|
||||
|
||||
internal static void InvokeOnRemove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value)
|
||||
{
|
||||
InvokeOnRemove(filter, value.value, value.view);
|
||||
}
|
||||
|
||||
internal static void InvokeOnRemove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view)
|
||||
{
|
||||
filter.OnCollectionChanged(ChangedKind.Remove, value, view);
|
||||
}
|
||||
|
||||
internal static void InvokeOnAttach<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view)
|
||||
{
|
||||
if (filter.IsMatch(value, view))
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ namespace ObservableCollections.Internal
|
||||
public FreezedView(IEnumerable<T> source, Func<T, TView> selector, bool reverse)
|
||||
{
|
||||
this.reverse = reverse;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||
this.list = source.Select(x => (x, selector(x))).ToList();
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ namespace ObservableCollections.Internal
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var (item, view) in list)
|
||||
@ -103,7 +103,7 @@ namespace ObservableCollections.Internal
|
||||
|
||||
public FreezedSortableView(IEnumerable<T> source, Func<T, TView> selector)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||
this.array = source.Select(x => (x, selector(x))).ToArray();
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@ namespace ObservableCollections.Internal
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var (item, view) in array)
|
||||
|
@ -47,7 +47,7 @@ namespace ObservableCollections
|
||||
{
|
||||
this.source = source;
|
||||
this.selector = selector;
|
||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
|
||||
this.SyncRoot = new object();
|
||||
lock (source.SyncRoot)
|
||||
{
|
||||
@ -83,7 +83,7 @@ namespace ObservableCollections
|
||||
this.filter = filter;
|
||||
foreach (var v in dict)
|
||||
{
|
||||
filter.Invoke(new KeyValuePair<TKey, TValue>(v.Key, v.Value.Item1), v.Value.Item2);
|
||||
filter.InvokeOnAttach(new KeyValuePair<TKey, TValue>(v.Key, v.Value.Item1), v.Value.Item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,7 +92,7 @@ namespace ObservableCollections
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var v in dict)
|
||||
@ -134,25 +134,40 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = selector(e.NewItem);
|
||||
dict.Add(e.NewItem.Key, (e.NewItem.Value, v));
|
||||
filter.Invoke(new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value), v);
|
||||
filter.InvokeOnAdd(new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value), v);
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
{
|
||||
dict.Remove(e.OldItem.Key);
|
||||
if (dict.Remove(e.OldItem.Key, out var v))
|
||||
{
|
||||
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(e.OldItem.Key, v.Item1), v.Item2));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Move:
|
||||
case NotifyCollectionChangedAction.Replace:
|
||||
{
|
||||
dict.Remove(e.OldItem.Key);
|
||||
if (dict.Remove(e.OldItem.Key, out var oldView))
|
||||
{
|
||||
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(e.OldItem.Key, oldView.Item1), oldView.Item2));
|
||||
}
|
||||
|
||||
var v = selector(e.NewItem);
|
||||
dict[e.NewItem.Key] = (e.NewItem.Value, v);
|
||||
filter.Invoke(new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value), v);
|
||||
filter.InvokeOnAdd(new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value), v);
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
{
|
||||
if (!filter.IsNullFilter())
|
||||
{
|
||||
foreach (var item in dict)
|
||||
{
|
||||
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2));
|
||||
}
|
||||
}
|
||||
|
||||
dict.Clear();
|
||||
}
|
||||
break;
|
||||
@ -177,7 +192,7 @@ namespace ObservableCollections
|
||||
{
|
||||
this.source = source;
|
||||
this.selector = selector;
|
||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
|
||||
this.SyncRoot = new object();
|
||||
lock (source.SyncRoot)
|
||||
{
|
||||
@ -217,7 +232,7 @@ namespace ObservableCollections
|
||||
this.filter = filter;
|
||||
foreach (var v in dict)
|
||||
{
|
||||
filter.Invoke(new KeyValuePair<TKey, TValue>(v.Key.Key, v.Key.Value), v.Value);
|
||||
filter.InvokeOnAttach(new KeyValuePair<TKey, TValue>(v.Key.Key, v.Key.Value), v.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -226,7 +241,7 @@ namespace ObservableCollections
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var v in dict)
|
||||
@ -269,27 +284,41 @@ namespace ObservableCollections
|
||||
var v = selector(e.NewItem);
|
||||
var k = new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value);
|
||||
dict.Add(k, v);
|
||||
filter.Invoke(k, v);
|
||||
filter.InvokeOnAdd(k, v);
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
{
|
||||
dict.Remove(e.OldItem);
|
||||
if (dict.Remove(e.OldItem, out var value))
|
||||
{
|
||||
filter.InvokeOnRemove(e.OldItem, value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Move:
|
||||
case NotifyCollectionChangedAction.Replace:
|
||||
{
|
||||
var k = new KeyValuePair<TKey, TValue>(e.OldItem.Key, e.OldItem.Value);
|
||||
dict.Remove(k);
|
||||
if (dict.Remove(k, out var oldValue))
|
||||
{
|
||||
filter.InvokeOnRemove(k, oldValue);
|
||||
}
|
||||
|
||||
var v = selector(e.NewItem);
|
||||
var nk = new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value);
|
||||
dict[nk] = v;
|
||||
filter.Invoke(nk, v);
|
||||
filter.InvokeOnAdd(nk, v);
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
{
|
||||
if (!filter.IsNullFilter())
|
||||
{
|
||||
foreach (var item in dict)
|
||||
{
|
||||
filter.InvokeOnRemove(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
dict.Clear();
|
||||
}
|
||||
break;
|
||||
@ -317,7 +346,7 @@ namespace ObservableCollections
|
||||
{
|
||||
this.source = source;
|
||||
this.selector = selector;
|
||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
|
||||
this.SyncRoot = new object();
|
||||
lock (source.SyncRoot)
|
||||
{
|
||||
@ -360,7 +389,7 @@ namespace ObservableCollections
|
||||
this.filter = filter;
|
||||
foreach (var v in dict)
|
||||
{
|
||||
filter.Invoke(v.Value, v.Key);
|
||||
filter.InvokeOnAttach(v.Value, v.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -369,7 +398,7 @@ namespace ObservableCollections
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var v in dict)
|
||||
@ -413,7 +442,7 @@ namespace ObservableCollections
|
||||
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);
|
||||
filter.InvokeOnAdd(k, v);
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
@ -421,6 +450,7 @@ namespace ObservableCollections
|
||||
if (viewMap.Remove(e.OldItem.Key, out var view))
|
||||
{
|
||||
dict.Remove(view);
|
||||
filter.InvokeOnRemove(e.OldItem, view);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -429,19 +459,30 @@ namespace ObservableCollections
|
||||
{
|
||||
if (viewMap.Remove(e.OldItem.Key, out var view))
|
||||
{
|
||||
dict.Remove(view);
|
||||
if (dict.Remove(view, out var oldView))
|
||||
{
|
||||
filter.InvokeOnRemove(e.OldItem, view);
|
||||
}
|
||||
|
||||
var v = selector(e.NewItem);
|
||||
var k = new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value);
|
||||
dict[v] = k;
|
||||
viewMap[e.NewItem.Key] = v;
|
||||
filter.Invoke(k, v);
|
||||
filter.InvokeOnAdd(k, v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
{
|
||||
if (!filter.IsNullFilter())
|
||||
{
|
||||
foreach (var item in dict)
|
||||
{
|
||||
filter.InvokeOnRemove(item.Value, item.Key);
|
||||
}
|
||||
}
|
||||
dict.Clear();
|
||||
viewMap.Clear();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -18,9 +18,9 @@ namespace ObservableCollections
|
||||
this.dictionary = new Dictionary<TKey, TValue>();
|
||||
}
|
||||
|
||||
public ObservableDictionary(Dictionary<TKey, TValue> dictionary)
|
||||
public ObservableDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection)
|
||||
{
|
||||
this.dictionary = dictionary;
|
||||
this.dictionary = new Dictionary<TKey, TValue>(collection);
|
||||
}
|
||||
|
||||
public event NotifyCollectionChangedEventHandler<KeyValuePair<TKey, TValue>>? CollectionChanged;
|
||||
|
15
src/ObservableCollections/ObservableLinkedList.cs
Normal file
15
src/ObservableCollections/ObservableLinkedList.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ObservableCollections
|
||||
{
|
||||
public sealed partial class ObservableLinkedList<T>
|
||||
{
|
||||
// TODO:not yet
|
||||
readonly LinkedList<T> list;
|
||||
|
||||
public ObservableLinkedList(LinkedList<T> list)
|
||||
{
|
||||
this.list = list;
|
||||
}
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ namespace ObservableCollections
|
||||
this.source = source;
|
||||
this.selector = selector;
|
||||
this.reverse = reverse;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||
this.SyncRoot = new object();
|
||||
lock (source.SyncRoot)
|
||||
{
|
||||
@ -54,10 +54,6 @@ namespace ObservableCollections
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void DoSort()
|
||||
{
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
@ -76,7 +72,7 @@ namespace ObservableCollections
|
||||
this.filter = filter;
|
||||
foreach (var (value, view) in list)
|
||||
{
|
||||
filter.Invoke(value, view);
|
||||
filter.InvokeOnAttach(value, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,7 +81,7 @@ namespace ObservableCollections
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var (item, view) in list)
|
||||
@ -139,7 +135,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (e.NewItem, selector(e.NewItem));
|
||||
list.Add(v);
|
||||
filter.Invoke(v);
|
||||
filter.InvokeOnAdd(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -147,7 +143,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (item, selector(item));
|
||||
list.Add(v);
|
||||
filter.Invoke(v);
|
||||
filter.InvokeOnAdd(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -158,7 +154,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (e.NewItem, selector(e.NewItem));
|
||||
list.Insert(e.NewStartingIndex, v);
|
||||
filter.Invoke(v);
|
||||
filter.InvokeOnAdd(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -169,7 +165,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (span[i], selector(span[i]));
|
||||
newArray[i] = v;
|
||||
filter.Invoke(v);
|
||||
filter.InvokeOnAdd(v);
|
||||
}
|
||||
list.InsertRange(e.NewStartingIndex, newArray);
|
||||
}
|
||||
@ -178,10 +174,22 @@ namespace ObservableCollections
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
if (e.IsSingleItem)
|
||||
{
|
||||
var v = list[e.OldStartingIndex];
|
||||
list.RemoveAt(e.OldStartingIndex);
|
||||
filter.InvokeOnRemove(v.Item1, v.Item2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!filter.IsNullFilter())
|
||||
{
|
||||
var len = e.OldStartingIndex + e.OldItems.Length;
|
||||
for (int i = e.OldStartingIndex; i < len; i++)
|
||||
{
|
||||
var v = list[i];
|
||||
filter.InvokeOnRemove(v.Item1, v.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
list.RemoveRange(e.OldStartingIndex, e.OldItems.Length);
|
||||
}
|
||||
break;
|
||||
@ -189,25 +197,39 @@ namespace ObservableCollections
|
||||
// ObservableList does not support replace range
|
||||
{
|
||||
var v = (e.NewItem, selector(e.NewItem));
|
||||
|
||||
var oldItem = list[e.NewStartingIndex];
|
||||
list[e.NewStartingIndex] = v;
|
||||
|
||||
filter.InvokeOnRemove(oldItem);
|
||||
filter.InvokeOnAdd(v);
|
||||
break;
|
||||
}
|
||||
case NotifyCollectionChangedAction.Move:
|
||||
{
|
||||
var v = (e.NewItem, selector(e.NewItem));
|
||||
var removeItem = list[e.OldStartingIndex];
|
||||
list.RemoveAt(e.OldStartingIndex);
|
||||
list.Insert(e.NewStartingIndex, v);
|
||||
filter.Invoke(v);
|
||||
|
||||
filter.InvokeOnRemove(removeItem);
|
||||
filter.InvokeOnAdd(v);
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
if (!filter.IsNullFilter())
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
filter.InvokeOnRemove(item);
|
||||
}
|
||||
}
|
||||
list.Clear();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
DoSort();
|
||||
RoutingCollectionChanged?.Invoke(e);
|
||||
CollectionStateChanged?.Invoke(e.Action);
|
||||
}
|
||||
@ -234,7 +256,7 @@ namespace ObservableCollections
|
||||
this.source = source;
|
||||
this.identitySelector = identitySelector;
|
||||
this.transform = transform;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||
lock (source.SyncRoot)
|
||||
{
|
||||
var dict = new SortedDictionary<(T, TKey), (T, TView)>(new Comparer(comparer));
|
||||
@ -268,7 +290,7 @@ namespace ObservableCollections
|
||||
this.filter = filter;
|
||||
foreach (var (_, (value, view)) in list)
|
||||
{
|
||||
filter.Invoke(value, view);
|
||||
filter.InvokeOnAttach(value, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -277,7 +299,7 @@ namespace ObservableCollections
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var (_, (value, view)) in list)
|
||||
@ -323,7 +345,7 @@ namespace ObservableCollections
|
||||
var view = transform(value);
|
||||
var id = identitySelector(value);
|
||||
list.Add((value, id), (value, view));
|
||||
filter.Invoke(value, view);
|
||||
filter.InvokeOnAdd(value, view);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -332,7 +354,7 @@ namespace ObservableCollections
|
||||
var view = transform(value);
|
||||
var id = identitySelector(value);
|
||||
list.Add((value, id), (value, view));
|
||||
filter.Invoke(value, view);
|
||||
filter.InvokeOnAdd(value, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -343,14 +365,16 @@ namespace ObservableCollections
|
||||
{
|
||||
var value = e.OldItem;
|
||||
var id = identitySelector(value);
|
||||
list.Remove((value, id));
|
||||
list.Remove((value, id), out var v);
|
||||
filter.InvokeOnRemove(v.Value, v.View);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var value in e.OldItems)
|
||||
{
|
||||
var id = identitySelector(value);
|
||||
list.Remove((value, id));
|
||||
list.Remove((value, id), out var v);
|
||||
filter.InvokeOnRemove(v.Value, v.View);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -361,16 +385,25 @@ namespace ObservableCollections
|
||||
// Replace is remove old item and insert new item(same index on replace, difference index on move).
|
||||
{
|
||||
var oldValue = e.OldItem;
|
||||
list.Remove((oldValue, identitySelector(oldValue)));
|
||||
list.Remove((oldValue, identitySelector(oldValue)), out var oldView);
|
||||
|
||||
var value = e.NewItem;
|
||||
var view = transform(value);
|
||||
var id = identitySelector(value);
|
||||
list.Add((value, id), (value, view));
|
||||
filter.Invoke(value, view);
|
||||
|
||||
filter.InvokeOnRemove(oldView);
|
||||
filter.InvokeOnAdd(value, view);
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
if (!filter.IsNullFilter())
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
filter.InvokeOnRemove(item.Value);
|
||||
}
|
||||
}
|
||||
list.Clear();
|
||||
break;
|
||||
default:
|
||||
@ -425,7 +458,7 @@ namespace ObservableCollections
|
||||
this.source = source;
|
||||
this.identitySelector = identitySelector;
|
||||
this.transform = transform;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||
lock (source.SyncRoot)
|
||||
{
|
||||
var dict = new SortedDictionary<(TView, TKey), (T, TView)>(new Comparer(comparer));
|
||||
@ -462,7 +495,7 @@ namespace ObservableCollections
|
||||
this.filter = filter;
|
||||
foreach (var (_, (value, view)) in list)
|
||||
{
|
||||
filter.Invoke(value, view);
|
||||
filter.InvokeOnAttach(value, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -471,7 +504,7 @@ namespace ObservableCollections
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue;
|
||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||
if (resetAction != null)
|
||||
{
|
||||
foreach (var (_, (value, view)) in list)
|
||||
@ -518,7 +551,7 @@ namespace ObservableCollections
|
||||
var id = identitySelector(value);
|
||||
list.Add((view, id), (value, view));
|
||||
viewMap.Add(id, view);
|
||||
filter.Invoke(value, view);
|
||||
filter.InvokeOnAdd(value, view);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -528,7 +561,7 @@ namespace ObservableCollections
|
||||
var id = identitySelector(value);
|
||||
list.Add((view, id), (value, view));
|
||||
viewMap.Add(id, view);
|
||||
filter.Invoke(value, view);
|
||||
filter.InvokeOnAdd(value, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -541,7 +574,8 @@ namespace ObservableCollections
|
||||
var id = identitySelector(value);
|
||||
if (viewMap.Remove(id, out var view))
|
||||
{
|
||||
list.Remove((view, id));
|
||||
list.Remove((view, id), out var v);
|
||||
filter.InvokeOnRemove(v);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -551,7 +585,8 @@ namespace ObservableCollections
|
||||
var id = identitySelector(value);
|
||||
if (viewMap.Remove(id, out var view))
|
||||
{
|
||||
list.Remove((view, id));
|
||||
list.Remove((view, id), out var v);
|
||||
filter.InvokeOnRemove(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -567,6 +602,7 @@ namespace ObservableCollections
|
||||
if (viewMap.Remove(oldKey, out var oldView))
|
||||
{
|
||||
list.Remove((oldView, oldKey));
|
||||
filter.InvokeOnRemove(oldValue, oldView);
|
||||
}
|
||||
|
||||
var value = e.NewItem;
|
||||
@ -574,11 +610,20 @@ namespace ObservableCollections
|
||||
var id = identitySelector(value);
|
||||
list.Add((view, id), (value, view));
|
||||
viewMap.Add(id, view);
|
||||
filter.Invoke(value, view);
|
||||
|
||||
filter.InvokeOnAdd(value, view);
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
if (!filter.IsNullFilter())
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
filter.InvokeOnRemove(item.Value);
|
||||
}
|
||||
}
|
||||
list.Clear();
|
||||
viewMap.Clear();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -17,9 +17,14 @@ namespace ObservableCollections
|
||||
list = new List<T>();
|
||||
}
|
||||
|
||||
public ObservableList(IEnumerable<T> source)
|
||||
public ObservableList(int capacity)
|
||||
{
|
||||
list = source.ToList();
|
||||
list = new List<T>(capacity);
|
||||
}
|
||||
|
||||
public ObservableList(IEnumerable<T> collection)
|
||||
{
|
||||
list = collection.ToList();
|
||||
}
|
||||
|
||||
public T this[int index]
|
||||
|
156
src/ObservableCollections/ObservableQueue.cs
Normal file
156
src/ObservableCollections/ObservableQueue.cs
Normal file
@ -0,0 +1,156 @@
|
||||
using ObservableCollections.Internal;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ObservableCollections
|
||||
{
|
||||
public sealed partial class ObservableQueue<T> : IReadOnlyCollection<T>, IObservableCollection<T>
|
||||
{
|
||||
readonly Queue<T> queue;
|
||||
public readonly object SyncRoot = new object();
|
||||
|
||||
public ObservableQueue()
|
||||
{
|
||||
this.queue = new Queue<T>();
|
||||
}
|
||||
|
||||
public ObservableQueue(int capacity)
|
||||
{
|
||||
this.queue = new Queue<T>(capacity);
|
||||
}
|
||||
|
||||
public ObservableQueue(IEnumerable<T> collection)
|
||||
{
|
||||
this.queue = new Queue<T>(collection);
|
||||
}
|
||||
|
||||
public event NotifyCollectionChangedEventHandler<T>? CollectionChanged;
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return queue.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(T item)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
var index = queue.Count;
|
||||
queue.Enqueue(item);
|
||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(item, index));
|
||||
}
|
||||
}
|
||||
|
||||
public void EnqueueRange(IEnumerable<T> items)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
var index = queue.Count;
|
||||
using (var xs = new CopyedCollection<T>(items))
|
||||
{
|
||||
foreach (var item in xs.Span)
|
||||
{
|
||||
queue.Enqueue(item);
|
||||
}
|
||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(xs.Span, index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EnqueueRange(T[] items)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
var index = queue.Count;
|
||||
foreach (var item in items)
|
||||
{
|
||||
queue.Enqueue(item);
|
||||
}
|
||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, index));
|
||||
}
|
||||
}
|
||||
|
||||
public void EnqueueRange(ReadOnlySpan<T> items)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
var index = queue.Count;
|
||||
foreach (var item in items)
|
||||
{
|
||||
queue.Enqueue(item);
|
||||
}
|
||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, index));
|
||||
}
|
||||
}
|
||||
|
||||
public void Dequeue()
|
||||
{
|
||||
// this.queue.
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// TryDequeue
|
||||
|
||||
// DequeueRange
|
||||
|
||||
void Clear()
|
||||
{
|
||||
}
|
||||
|
||||
//bool Contains(T item)
|
||||
//{
|
||||
//}
|
||||
|
||||
//void CopyTo(T[] array, int arrayIndex);
|
||||
|
||||
// Peek
|
||||
|
||||
// ToArray
|
||||
|
||||
// TrimExcess
|
||||
|
||||
// EnsureCapacity
|
||||
|
||||
|
||||
|
||||
// TryPeek
|
||||
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ISynchronizedView<T, TView> CreateSortedView<TKey, TView>(Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<T> comparer) where TKey : notnull
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ISynchronizedView<T, TView> CreateSortedView<TKey, TView>(Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> viewComparer) where TKey : notnull
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
48
src/ObservableCollections/ObservableRingBuffer.cs
Normal file
48
src/ObservableCollections/ObservableRingBuffer.cs
Normal file
@ -0,0 +1,48 @@
|
||||
namespace ObservableCollections
|
||||
{
|
||||
public sealed partial class ObservableRingBuffer<T>
|
||||
{
|
||||
// TODO:not yet.
|
||||
readonly T[] buffer;
|
||||
|
||||
public ObservableRingBuffer(int capacity)
|
||||
{
|
||||
this.buffer = new T[capacity];
|
||||
}
|
||||
|
||||
public int Count => buffer.Length;
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.buffer[index];
|
||||
}
|
||||
set
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void AddLast()
|
||||
{
|
||||
// AddLast
|
||||
// AddFirst
|
||||
//new LinkedList<int>().remo
|
||||
//new Stack<int>().Push
|
||||
}
|
||||
|
||||
public void AddFirst()
|
||||
{
|
||||
}
|
||||
|
||||
public void RemoveLast()
|
||||
{
|
||||
}
|
||||
|
||||
public void RemoveFirst()
|
||||
{
|
||||
}
|
||||
|
||||
// GetReverseEnumerable
|
||||
}
|
||||
}
|
25
src/ObservableCollections/ObservableStack.cs
Normal file
25
src/ObservableCollections/ObservableStack.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ObservableCollections
|
||||
{
|
||||
public sealed partial class ObservableStack<T>
|
||||
{
|
||||
// TODO:not yet.
|
||||
readonly Stack<T> stack;
|
||||
|
||||
public ObservableStack(Stack<T> stack)
|
||||
{
|
||||
this.stack = stack;
|
||||
}
|
||||
|
||||
public void Push(T item)
|
||||
{
|
||||
stack.Push(item);
|
||||
}
|
||||
|
||||
public void Pop(T item)
|
||||
{
|
||||
stack.Pop();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user