new filter

This commit is contained in:
neuecc 2021-08-09 19:06:01 +09:00
parent c0fb7375e0
commit 59300d8ee8
10 changed files with 444 additions and 66 deletions

View File

@ -7,32 +7,42 @@ namespace ObservableCollections
bool IsMatch(T value, TView view); bool IsMatch(T value, TView view);
void WhenTrue(T value, TView view); void WhenTrue(T value, TView view);
void WhenFalse(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 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 Func<T, TView, bool> isMatch;
readonly Action<T, TView>? whenTrue; readonly Action<T, TView>? whenTrue;
readonly Action<T, TView>? whenFalse; 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.isMatch = isMatch;
this.whenTrue = whenTrue; this.whenTrue = whenTrue;
this.whenFalse = whenFalse; this.whenFalse = whenFalse;
this.onCollectionChanged = onCollectionChanged;
} }
public bool IsMatch(T value, TView view) => isMatch(value, view); public bool IsMatch(T value, TView view) => isMatch(value, view);
public void WhenFalse(T value, TView view) => whenFalse?.Invoke(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 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 bool IsMatch(T value, TView view) => true;
public void WhenFalse(T value, TView view) { } public void WhenFalse(T value, TView view) { }
public void WhenTrue(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) 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) 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)) if (filter.IsMatch(value, view))
{ {

View File

@ -23,7 +23,7 @@ namespace ObservableCollections.Internal
public FreezedView(IEnumerable<T> source, Func<T, TView> selector, bool reverse) public FreezedView(IEnumerable<T> source, Func<T, TView> selector, bool reverse)
{ {
this.reverse = 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(); this.list = source.Select(x => (x, selector(x))).ToList();
} }
@ -54,7 +54,7 @@ namespace ObservableCollections.Internal
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue; this.filter = SynchronizedViewFilter<T, TView>.Null;
if (resetAction != null) if (resetAction != null)
{ {
foreach (var (item, view) in list) foreach (var (item, view) in list)
@ -103,7 +103,7 @@ namespace ObservableCollections.Internal
public FreezedSortableView(IEnumerable<T> source, Func<T, TView> selector) 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(); this.array = source.Select(x => (x, selector(x))).ToArray();
} }
@ -134,7 +134,7 @@ namespace ObservableCollections.Internal
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue; this.filter = SynchronizedViewFilter<T, TView>.Null;
if (resetAction != null) if (resetAction != null)
{ {
foreach (var (item, view) in array) foreach (var (item, view) in array)

View File

@ -47,7 +47,7 @@ namespace ObservableCollections
{ {
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.AlwaysTrue; this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
@ -83,7 +83,7 @@ namespace ObservableCollections
this.filter = filter; this.filter = filter;
foreach (var v in dict) 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) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.AlwaysTrue; this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
if (resetAction != null) if (resetAction != null)
{ {
foreach (var v in dict) foreach (var v in dict)
@ -134,25 +134,40 @@ namespace ObservableCollections
{ {
var v = selector(e.NewItem); var v = selector(e.NewItem);
dict.Add(e.NewItem.Key, (e.NewItem.Value, v)); 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; break;
case NotifyCollectionChangedAction.Remove: 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; break;
case NotifyCollectionChangedAction.Move: case NotifyCollectionChangedAction.Move:
case NotifyCollectionChangedAction.Replace: 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); var v = selector(e.NewItem);
dict[e.NewItem.Key] = (e.NewItem.Value, v); 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; break;
case NotifyCollectionChangedAction.Reset: 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(); dict.Clear();
} }
break; break;
@ -177,7 +192,7 @@ namespace ObservableCollections
{ {
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.AlwaysTrue; this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
@ -217,7 +232,7 @@ namespace ObservableCollections
this.filter = filter; this.filter = filter;
foreach (var v in dict) 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) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.AlwaysTrue; this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
if (resetAction != null) if (resetAction != null)
{ {
foreach (var v in dict) foreach (var v in dict)
@ -269,27 +284,41 @@ namespace ObservableCollections
var v = selector(e.NewItem); var v = selector(e.NewItem);
var k = new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value); var k = new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value);
dict.Add(k, v); dict.Add(k, v);
filter.Invoke(k, v); filter.InvokeOnAdd(k, v);
} }
break; break;
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
{ {
dict.Remove(e.OldItem); if (dict.Remove(e.OldItem, out var value))
{
filter.InvokeOnRemove(e.OldItem, value);
}
} }
break; break;
case NotifyCollectionChangedAction.Move: case NotifyCollectionChangedAction.Move:
case NotifyCollectionChangedAction.Replace: case NotifyCollectionChangedAction.Replace:
{ {
var k = new KeyValuePair<TKey, TValue>(e.OldItem.Key, e.OldItem.Value); 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 v = selector(e.NewItem);
var nk = new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value); var nk = new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value);
dict[nk] = v; dict[nk] = v;
filter.Invoke(nk, v); filter.InvokeOnAdd(nk, v);
} }
break; break;
case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Reset:
{ {
if (!filter.IsNullFilter())
{
foreach (var item in dict)
{
filter.InvokeOnRemove(item.Key, item.Value);
}
}
dict.Clear(); dict.Clear();
} }
break; break;
@ -317,7 +346,7 @@ namespace ObservableCollections
{ {
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.AlwaysTrue; this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
@ -360,7 +389,7 @@ namespace ObservableCollections
this.filter = filter; this.filter = filter;
foreach (var v in dict) 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) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.AlwaysTrue; this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
if (resetAction != null) if (resetAction != null)
{ {
foreach (var v in dict) foreach (var v in dict)
@ -413,7 +442,7 @@ namespace ObservableCollections
var k = new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value); var k = new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value);
dict.Add(v, k); dict.Add(v, k);
viewMap.Add(e.NewItem.Key, v); viewMap.Add(e.NewItem.Key, v);
filter.Invoke(k, v); filter.InvokeOnAdd(k, v);
} }
break; break;
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
@ -421,6 +450,7 @@ namespace ObservableCollections
if (viewMap.Remove(e.OldItem.Key, out var view)) if (viewMap.Remove(e.OldItem.Key, out var view))
{ {
dict.Remove(view); dict.Remove(view);
filter.InvokeOnRemove(e.OldItem, view);
} }
} }
break; break;
@ -429,19 +459,30 @@ namespace ObservableCollections
{ {
if (viewMap.Remove(e.OldItem.Key, out var view)) 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 v = selector(e.NewItem);
var k = new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value); var k = new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value);
dict[v] = k; dict[v] = k;
viewMap[e.NewItem.Key] = v; viewMap[e.NewItem.Key] = v;
filter.Invoke(k, v); filter.InvokeOnAdd(k, v);
} }
break; break;
} }
case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Reset:
{ {
if (!filter.IsNullFilter())
{
foreach (var item in dict)
{
filter.InvokeOnRemove(item.Value, item.Key);
}
}
dict.Clear(); dict.Clear();
viewMap.Clear();
} }
break; break;
default: default:

View File

@ -18,9 +18,9 @@ namespace ObservableCollections
this.dictionary = new Dictionary<TKey, TValue>(); 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; public event NotifyCollectionChangedEventHandler<KeyValuePair<TKey, TValue>>? CollectionChanged;

View 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;
}
}
}

View File

@ -45,7 +45,7 @@ namespace ObservableCollections
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.reverse = reverse; this.reverse = reverse;
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue; this.filter = SynchronizedViewFilter<T, TView>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
@ -54,10 +54,6 @@ namespace ObservableCollections
} }
} }
protected virtual void DoSort()
{
}
public int Count public int Count
{ {
get get
@ -76,7 +72,7 @@ namespace ObservableCollections
this.filter = filter; this.filter = filter;
foreach (var (value, view) in list) foreach (var (value, view) in list)
{ {
filter.Invoke(value, view); filter.InvokeOnAttach(value, view);
} }
} }
} }
@ -85,7 +81,7 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue; this.filter = SynchronizedViewFilter<T, TView>.Null;
if (resetAction != null) if (resetAction != null)
{ {
foreach (var (item, view) in list) foreach (var (item, view) in list)
@ -139,7 +135,7 @@ namespace ObservableCollections
{ {
var v = (e.NewItem, selector(e.NewItem)); var v = (e.NewItem, selector(e.NewItem));
list.Add(v); list.Add(v);
filter.Invoke(v); filter.InvokeOnAdd(v);
} }
else else
{ {
@ -147,7 +143,7 @@ namespace ObservableCollections
{ {
var v = (item, selector(item)); var v = (item, selector(item));
list.Add(v); list.Add(v);
filter.Invoke(v); filter.InvokeOnAdd(v);
} }
} }
} }
@ -158,7 +154,7 @@ namespace ObservableCollections
{ {
var v = (e.NewItem, selector(e.NewItem)); var v = (e.NewItem, selector(e.NewItem));
list.Insert(e.NewStartingIndex, v); list.Insert(e.NewStartingIndex, v);
filter.Invoke(v); filter.InvokeOnAdd(v);
} }
else else
{ {
@ -169,7 +165,7 @@ namespace ObservableCollections
{ {
var v = (span[i], selector(span[i])); var v = (span[i], selector(span[i]));
newArray[i] = v; newArray[i] = v;
filter.Invoke(v); filter.InvokeOnAdd(v);
} }
list.InsertRange(e.NewStartingIndex, newArray); list.InsertRange(e.NewStartingIndex, newArray);
} }
@ -178,10 +174,22 @@ namespace ObservableCollections
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
if (e.IsSingleItem) if (e.IsSingleItem)
{ {
var v = list[e.OldStartingIndex];
list.RemoveAt(e.OldStartingIndex); list.RemoveAt(e.OldStartingIndex);
filter.InvokeOnRemove(v.Item1, v.Item2);
} }
else 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); list.RemoveRange(e.OldStartingIndex, e.OldItems.Length);
} }
break; break;
@ -189,25 +197,39 @@ namespace ObservableCollections
// ObservableList does not support replace range // ObservableList does not support replace range
{ {
var v = (e.NewItem, selector(e.NewItem)); var v = (e.NewItem, selector(e.NewItem));
var oldItem = list[e.NewStartingIndex];
list[e.NewStartingIndex] = v; list[e.NewStartingIndex] = v;
filter.InvokeOnRemove(oldItem);
filter.InvokeOnAdd(v);
break; break;
} }
case NotifyCollectionChangedAction.Move: case NotifyCollectionChangedAction.Move:
{ {
var v = (e.NewItem, selector(e.NewItem)); var v = (e.NewItem, selector(e.NewItem));
var removeItem = list[e.OldStartingIndex];
list.RemoveAt(e.OldStartingIndex); list.RemoveAt(e.OldStartingIndex);
list.Insert(e.NewStartingIndex, v); list.Insert(e.NewStartingIndex, v);
filter.Invoke(v);
filter.InvokeOnRemove(removeItem);
filter.InvokeOnAdd(v);
} }
break; break;
case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Reset:
if (!filter.IsNullFilter())
{
foreach (var item in list)
{
filter.InvokeOnRemove(item);
}
}
list.Clear(); list.Clear();
break; break;
default: default:
break; break;
} }
DoSort();
RoutingCollectionChanged?.Invoke(e); RoutingCollectionChanged?.Invoke(e);
CollectionStateChanged?.Invoke(e.Action); CollectionStateChanged?.Invoke(e.Action);
} }
@ -234,7 +256,7 @@ namespace ObservableCollections
this.source = source; this.source = source;
this.identitySelector = identitySelector; this.identitySelector = identitySelector;
this.transform = transform; this.transform = transform;
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue; this.filter = SynchronizedViewFilter<T, TView>.Null;
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
var dict = new SortedDictionary<(T, TKey), (T, TView)>(new Comparer(comparer)); var dict = new SortedDictionary<(T, TKey), (T, TView)>(new Comparer(comparer));
@ -268,7 +290,7 @@ namespace ObservableCollections
this.filter = filter; this.filter = filter;
foreach (var (_, (value, view)) in list) foreach (var (_, (value, view)) in list)
{ {
filter.Invoke(value, view); filter.InvokeOnAttach(value, view);
} }
} }
} }
@ -277,7 +299,7 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue; this.filter = SynchronizedViewFilter<T, TView>.Null;
if (resetAction != null) if (resetAction != null)
{ {
foreach (var (_, (value, view)) in list) foreach (var (_, (value, view)) in list)
@ -323,7 +345,7 @@ namespace ObservableCollections
var view = transform(value); var view = transform(value);
var id = identitySelector(value); var id = identitySelector(value);
list.Add((value, id), (value, view)); list.Add((value, id), (value, view));
filter.Invoke(value, view); filter.InvokeOnAdd(value, view);
} }
else else
{ {
@ -332,7 +354,7 @@ namespace ObservableCollections
var view = transform(value); var view = transform(value);
var id = identitySelector(value); var id = identitySelector(value);
list.Add((value, id), (value, view)); 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 value = e.OldItem;
var id = identitySelector(value); var id = identitySelector(value);
list.Remove((value, id)); list.Remove((value, id), out var v);
filter.InvokeOnRemove(v.Value, v.View);
} }
else else
{ {
foreach (var value in e.OldItems) foreach (var value in e.OldItems)
{ {
var id = identitySelector(value); 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). // Replace is remove old item and insert new item(same index on replace, difference index on move).
{ {
var oldValue = e.OldItem; var oldValue = e.OldItem;
list.Remove((oldValue, identitySelector(oldValue))); list.Remove((oldValue, identitySelector(oldValue)), out var oldView);
var value = e.NewItem; var value = e.NewItem;
var view = transform(value); var view = transform(value);
var id = identitySelector(value); var id = identitySelector(value);
list.Add((value, id), (value, view)); list.Add((value, id), (value, view));
filter.Invoke(value, view);
filter.InvokeOnRemove(oldView);
filter.InvokeOnAdd(value, view);
} }
break; break;
case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Reset:
if (!filter.IsNullFilter())
{
foreach (var item in list)
{
filter.InvokeOnRemove(item.Value);
}
}
list.Clear(); list.Clear();
break; break;
default: default:
@ -425,7 +458,7 @@ namespace ObservableCollections
this.source = source; this.source = source;
this.identitySelector = identitySelector; this.identitySelector = identitySelector;
this.transform = transform; this.transform = transform;
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue; this.filter = SynchronizedViewFilter<T, TView>.Null;
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
var dict = new SortedDictionary<(TView, TKey), (T, TView)>(new Comparer(comparer)); var dict = new SortedDictionary<(TView, TKey), (T, TView)>(new Comparer(comparer));
@ -462,7 +495,7 @@ namespace ObservableCollections
this.filter = filter; this.filter = filter;
foreach (var (_, (value, view)) in list) foreach (var (_, (value, view)) in list)
{ {
filter.Invoke(value, view); filter.InvokeOnAttach(value, view);
} }
} }
} }
@ -471,7 +504,7 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T, TView>.AlwaysTrue; this.filter = SynchronizedViewFilter<T, TView>.Null;
if (resetAction != null) if (resetAction != null)
{ {
foreach (var (_, (value, view)) in list) foreach (var (_, (value, view)) in list)
@ -518,7 +551,7 @@ namespace ObservableCollections
var id = identitySelector(value); var id = identitySelector(value);
list.Add((view, id), (value, view)); list.Add((view, id), (value, view));
viewMap.Add(id, view); viewMap.Add(id, view);
filter.Invoke(value, view); filter.InvokeOnAdd(value, view);
} }
else else
{ {
@ -528,7 +561,7 @@ namespace ObservableCollections
var id = identitySelector(value); var id = identitySelector(value);
list.Add((view, id), (value, view)); list.Add((view, id), (value, view));
viewMap.Add(id, view); viewMap.Add(id, view);
filter.Invoke(value, view); filter.InvokeOnAdd(value, view);
} }
} }
} }
@ -541,7 +574,8 @@ namespace ObservableCollections
var id = identitySelector(value); var id = identitySelector(value);
if (viewMap.Remove(id, out var view)) if (viewMap.Remove(id, out var view))
{ {
list.Remove((view, id)); list.Remove((view, id), out var v);
filter.InvokeOnRemove(v);
} }
} }
else else
@ -551,7 +585,8 @@ namespace ObservableCollections
var id = identitySelector(value); var id = identitySelector(value);
if (viewMap.Remove(id, out var view)) 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)) if (viewMap.Remove(oldKey, out var oldView))
{ {
list.Remove((oldView, oldKey)); list.Remove((oldView, oldKey));
filter.InvokeOnRemove(oldValue, oldView);
} }
var value = e.NewItem; var value = e.NewItem;
@ -574,11 +610,20 @@ namespace ObservableCollections
var id = identitySelector(value); var id = identitySelector(value);
list.Add((view, id), (value, view)); list.Add((view, id), (value, view));
viewMap.Add(id, view); viewMap.Add(id, view);
filter.Invoke(value, view);
filter.InvokeOnAdd(value, view);
} }
break; break;
case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Reset:
if (!filter.IsNullFilter())
{
foreach (var item in list)
{
filter.InvokeOnRemove(item.Value);
}
}
list.Clear(); list.Clear();
viewMap.Clear();
break; break;
default: default:
break; break;

View File

@ -17,9 +17,14 @@ namespace ObservableCollections
list = new List<T>(); 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] public T this[int index]

View 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();
}
}
}

View 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
}
}

View 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();
}
}
}