Support for firing add event for initial elements
This commit is contained in:
parent
bcf250c631
commit
7b75bf2940
@ -1,24 +1,66 @@
|
|||||||
using ObservableCollections;
|
using System;
|
||||||
using System;
|
using System.Linq;
|
||||||
using System.Collections.Specialized;
|
using ObservableCollections;
|
||||||
|
|
||||||
|
var models = new ObservableList<int>(Enumerable.Range(0, 10));
|
||||||
|
|
||||||
|
var viewModels = models.CreateView(x => new ViewModel
|
||||||
// Basic sample, use like ObservableCollection<T>.
|
|
||||||
// CollectionChanged observes all collection modification
|
|
||||||
var list = new ObservableList<int>();
|
|
||||||
var view = list.CreateView(x => x.ToString() + "$");
|
|
||||||
|
|
||||||
list.Add(10);
|
|
||||||
list.Add(20);
|
|
||||||
list.AddRange(new[] { 30, 40, 50 });
|
|
||||||
list[1] = 60;
|
|
||||||
list.RemoveAt(3);
|
|
||||||
|
|
||||||
foreach (var (_, v) in view)
|
|
||||||
{
|
{
|
||||||
// 10$, 60$, 30$, 50$
|
Id = x,
|
||||||
Console.WriteLine(v);
|
Value = "@" + x
|
||||||
|
});
|
||||||
|
|
||||||
|
viewModels.AttachFilter(new HogeFilter(), true);
|
||||||
|
|
||||||
|
models.Add(100);
|
||||||
|
|
||||||
|
foreach (var (x, xs) in viewModels)
|
||||||
|
{
|
||||||
|
System.Console.WriteLine(xs.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispose view is unsubscribe collection changed event.
|
class ViewModel
|
||||||
view.Dispose();
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class HogeFilter : ISynchronizedViewFilter<int, ViewModel>
|
||||||
|
{
|
||||||
|
public bool IsMatch(int value, ViewModel view)
|
||||||
|
{
|
||||||
|
return value % 2 == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WhenTrue(int value, ViewModel view)
|
||||||
|
{
|
||||||
|
view.Value = $"@{value} (even)";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WhenFalse(int value, ViewModel view)
|
||||||
|
{
|
||||||
|
view.Value = $"@{value} (odd)";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCollectionChanged(
|
||||||
|
ChangedKind changedKind,
|
||||||
|
int value,
|
||||||
|
ViewModel view,
|
||||||
|
in NotifyCollectionChangedEventArgs<int> eventArgs)
|
||||||
|
{
|
||||||
|
switch (changedKind)
|
||||||
|
{
|
||||||
|
case ChangedKind.Add:
|
||||||
|
view.Value += " Add";
|
||||||
|
break;
|
||||||
|
case ChangedKind.Remove:
|
||||||
|
view.Value += " Remove";
|
||||||
|
break;
|
||||||
|
case ChangedKind.Move:
|
||||||
|
view.Value += $" Move {eventArgs.OldStartingIndex} {eventArgs.NewStartingIndex}";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(changedKind), changedKind, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -28,7 +28,7 @@ namespace ObservableCollections
|
|||||||
event NotifyCollectionChangedEventHandler<T> RoutingCollectionChanged;
|
event NotifyCollectionChangedEventHandler<T> RoutingCollectionChanged;
|
||||||
event Action<NotifyCollectionChangedAction> CollectionStateChanged;
|
event Action<NotifyCollectionChangedAction> CollectionStateChanged;
|
||||||
|
|
||||||
void AttachFilter(ISynchronizedViewFilter<T, TView> filter);
|
void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForInitialElements = false);
|
||||||
void ResetFilter(Action<T, TView> resetAction);
|
void ResetFilter(Action<T, TView> resetAction);
|
||||||
INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged();
|
INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged();
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ namespace ObservableCollections.Internal
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var array = ArrayPool<T>.Shared.Rent(count);
|
var array = ArrayPool<T>.Shared.Rent(16);
|
||||||
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
foreach (var item in source)
|
foreach (var item in source)
|
||||||
@ -75,8 +75,8 @@ namespace ObservableCollections.Internal
|
|||||||
if (array.Length == index)
|
if (array.Length == index)
|
||||||
{
|
{
|
||||||
ArrayPool<T>.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
|
ArrayPool<T>.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
|
||||||
|
array = ArrayPool<T>.Shared.Rent(index * 2);
|
||||||
}
|
}
|
||||||
array = ArrayPool<T>.Shared.Rent(index * 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -38,14 +38,22 @@ namespace ObservableCollections.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var (value, view) in list)
|
for (var i = 0; i < list.Count; i++)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
var (value, view) = list[i];
|
||||||
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,14 +141,22 @@ namespace ObservableCollections.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var (value, view) in array)
|
for (var i = 0; i < array.Length; i++)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
var (value, view) = array[i];
|
||||||
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,7 +194,6 @@ namespace ObservableCollections.Internal
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Sort(IComparer<T> comparer)
|
public void Sort(IComparer<T> comparer)
|
||||||
|
@ -55,7 +55,7 @@ namespace ObservableCollections.Internal
|
|||||||
remove { parent.RoutingCollectionChanged -= value; }
|
remove { parent.RoutingCollectionChanged -= value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter) => parent.AttachFilter(filter);
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false) => parent.AttachFilter(filter, invokeAddEventForCurrentElements);
|
||||||
public void ResetFilter(Action<T, TView> resetAction) => parent.ResetFilter(resetAction);
|
public void ResetFilter(Action<T, TView> resetAction) => parent.ResetFilter(resetAction);
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged() => this;
|
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged() => this;
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -51,14 +51,21 @@ namespace ObservableCollections.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var (_, (value, view)) in dict)
|
foreach (var (_, (value, view)) in dict)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, -1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,14 +55,21 @@ namespace ObservableCollections.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var (_, (value, view)) in dict)
|
foreach (var (_, (value, view)) in dict)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, -1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,14 +55,23 @@ namespace ObservableCollections
|
|||||||
this.source.CollectionChanged -= SourceCollectionChanged;
|
this.source.CollectionChanged -= SourceCollectionChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var v in dict)
|
foreach (var v in dict)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(new KeyValuePair<TKey, TValue>(v.Key, v.Value.Item1), v.Value.Item2);
|
var value = new KeyValuePair<TKey, TValue>(v.Key, v.Value.Item1);
|
||||||
|
var view = v.Value.Item2;
|
||||||
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>>.Add(value, -1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,44 +127,44 @@ namespace ObservableCollections
|
|||||||
switch (e.Action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
case NotifyCollectionChangedAction.Add:
|
case NotifyCollectionChangedAction.Add:
|
||||||
{
|
{
|
||||||
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.InvokeOnAdd(new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value), v, e);
|
filter.InvokeOnAdd(new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value), v, e);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Remove:
|
case NotifyCollectionChangedAction.Remove:
|
||||||
|
{
|
||||||
|
if (dict.Remove(e.OldItem.Key, out var v))
|
||||||
{
|
{
|
||||||
if (dict.Remove(e.OldItem.Key, out var v))
|
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(e.OldItem.Key, v.Item1), v.Item2), e);
|
||||||
{
|
|
||||||
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(e.OldItem.Key, v.Item1), v.Item2), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Replace:
|
case NotifyCollectionChangedAction.Replace:
|
||||||
|
{
|
||||||
|
if (dict.Remove(e.OldItem.Key, out var oldView))
|
||||||
{
|
{
|
||||||
if (dict.Remove(e.OldItem.Key, out var oldView))
|
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(e.OldItem.Key, oldView.Item1), oldView.Item2), e);
|
||||||
{
|
|
||||||
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(e.OldItem.Key, oldView.Item1), oldView.Item2), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
var v = selector(e.NewItem);
|
|
||||||
dict[e.NewItem.Key] = (e.NewItem.Value, v);
|
|
||||||
filter.InvokeOnAdd(new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value), v, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var v = selector(e.NewItem);
|
||||||
|
dict[e.NewItem.Key] = (e.NewItem.Value, v);
|
||||||
|
filter.InvokeOnAdd(new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value), v, e);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Reset:
|
case NotifyCollectionChangedAction.Reset:
|
||||||
|
{
|
||||||
|
if (!filter.IsNullFilter())
|
||||||
{
|
{
|
||||||
if (!filter.IsNullFilter())
|
foreach (var item in dict)
|
||||||
{
|
{
|
||||||
foreach (var item in dict)
|
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2), e);
|
||||||
{
|
|
||||||
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dict.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dict.Clear();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Move: // ObservableDictionary have no Move operation.
|
case NotifyCollectionChangedAction.Move: // ObservableDictionary have no Move operation.
|
||||||
default:
|
default:
|
||||||
@ -168,4 +177,4 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -51,14 +51,21 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var (_, (value, view)) in dict)
|
foreach (var (_, (value, view)) in dict)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd((value, view), NotifyCollectionChangedEventArgs<T>.Add(value, -1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,14 +53,23 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var (value, view) in list)
|
for (var i = 0; i < list.Count; i++)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
var (value, view) = list[i];
|
||||||
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
var eventArgs = NotifyCollectionChangedEventArgs<T>.Add(value, i);
|
||||||
|
filter.InvokeOnAdd(value, view, eventArgs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,24 +202,24 @@ namespace ObservableCollections
|
|||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Replace:
|
case NotifyCollectionChangedAction.Replace:
|
||||||
// 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];
|
var oldItem = list[e.NewStartingIndex];
|
||||||
list[e.NewStartingIndex] = v;
|
list[e.NewStartingIndex] = v;
|
||||||
|
|
||||||
filter.InvokeOnRemove(oldItem, e);
|
filter.InvokeOnRemove(oldItem, e);
|
||||||
filter.InvokeOnAdd(v, e);
|
filter.InvokeOnAdd(v, e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NotifyCollectionChangedAction.Move:
|
case NotifyCollectionChangedAction.Move:
|
||||||
{
|
{
|
||||||
var removeItem = list[e.OldStartingIndex];
|
var removeItem = list[e.OldStartingIndex];
|
||||||
list.RemoveAt(e.OldStartingIndex);
|
list.RemoveAt(e.OldStartingIndex);
|
||||||
list.Insert(e.NewStartingIndex, removeItem);
|
list.Insert(e.NewStartingIndex, removeItem);
|
||||||
|
|
||||||
filter.InvokeOnMove(removeItem, e);
|
filter.InvokeOnMove(removeItem, e);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Reset:
|
case NotifyCollectionChangedAction.Reset:
|
||||||
if (!filter.IsNullFilter())
|
if (!filter.IsNullFilter())
|
||||||
|
@ -53,14 +53,23 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
|
var i = 0;
|
||||||
foreach (var (value, view) in queue)
|
foreach (var (value, view) in queue)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,14 +54,22 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var (value, view) in ringBuffer)
|
for (var i = 0; i < ringBuffer.Count; i++)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
var (value, view) = ringBuffer[i];
|
||||||
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,14 +53,23 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
|
var i = 0;
|
||||||
foreach (var (value, view) in stack)
|
foreach (var (value, view) in stack)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
#if (NETSTANDARD2_0 || NET_STANDARD_2_0 || NET_4_6) && !UNITY_2021_1_OR_NEWER
|
#if NETSTANDARD2_0 || NET_STANDARD_2_0 || NET_4_6
|
||||||
|
|
||||||
namespace System.Diagnostics.CodeAnalysis
|
namespace System.Diagnostics.CodeAnalysis
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,7 @@ namespace ObservableCollections
|
|||||||
event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
||||||
event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||||
|
|
||||||
void AttachFilter(ISynchronizedViewFilter<T, TView> filter);
|
void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForInitialElements = false);
|
||||||
void ResetFilter(Action<T, TView>? resetAction);
|
void ResetFilter(Action<T, TView>? resetAction);
|
||||||
INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged();
|
INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged();
|
||||||
}
|
}
|
||||||
|
@ -38,14 +38,22 @@ namespace ObservableCollections.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var (value, view) in list)
|
for (var i = 0; i < list.Count; i++)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
var (value, view) = list[i];
|
||||||
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,14 +141,22 @@ namespace ObservableCollections.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var (value, view) in array)
|
for (var i = 0; i < array.Length; i++)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
var (value, view) = array[i];
|
||||||
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,7 +194,6 @@ namespace ObservableCollections.Internal
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Sort(IComparer<T> comparer)
|
public void Sort(IComparer<T> comparer)
|
||||||
|
@ -55,7 +55,7 @@ namespace ObservableCollections.Internal
|
|||||||
remove { parent.RoutingCollectionChanged -= value; }
|
remove { parent.RoutingCollectionChanged -= value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter) => parent.AttachFilter(filter);
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false) => parent.AttachFilter(filter, invokeAddEventForCurrentElements);
|
||||||
public void ResetFilter(Action<T, TView>? resetAction) => parent.ResetFilter(resetAction);
|
public void ResetFilter(Action<T, TView>? resetAction) => parent.ResetFilter(resetAction);
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged() => this;
|
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged() => this;
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -51,14 +51,21 @@ namespace ObservableCollections.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var (_, (value, view)) in dict)
|
foreach (var (_, (value, view)) in dict)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, -1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,14 +55,21 @@ namespace ObservableCollections.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var (_, (value, view)) in dict)
|
foreach (var (_, (value, view)) in dict)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, -1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,14 +55,23 @@ namespace ObservableCollections
|
|||||||
this.source.CollectionChanged -= SourceCollectionChanged;
|
this.source.CollectionChanged -= SourceCollectionChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var v in dict)
|
foreach (var v in dict)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(new KeyValuePair<TKey, TValue>(v.Key, v.Value.Item1), v.Value.Item2);
|
var value = new KeyValuePair<TKey, TValue>(v.Key, v.Value.Item1);
|
||||||
|
var view = v.Value.Item2;
|
||||||
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>>.Add(value, -1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,44 +127,44 @@ namespace ObservableCollections
|
|||||||
switch (e.Action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
case NotifyCollectionChangedAction.Add:
|
case NotifyCollectionChangedAction.Add:
|
||||||
{
|
{
|
||||||
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.InvokeOnAdd(new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value), v, e);
|
filter.InvokeOnAdd(new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value), v, e);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Remove:
|
case NotifyCollectionChangedAction.Remove:
|
||||||
|
{
|
||||||
|
if (dict.Remove(e.OldItem.Key, out var v))
|
||||||
{
|
{
|
||||||
if (dict.Remove(e.OldItem.Key, out var v))
|
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(e.OldItem.Key, v.Item1), v.Item2), e);
|
||||||
{
|
|
||||||
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(e.OldItem.Key, v.Item1), v.Item2), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Replace:
|
case NotifyCollectionChangedAction.Replace:
|
||||||
|
{
|
||||||
|
if (dict.Remove(e.OldItem.Key, out var oldView))
|
||||||
{
|
{
|
||||||
if (dict.Remove(e.OldItem.Key, out var oldView))
|
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(e.OldItem.Key, oldView.Item1), oldView.Item2), e);
|
||||||
{
|
|
||||||
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(e.OldItem.Key, oldView.Item1), oldView.Item2), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
var v = selector(e.NewItem);
|
|
||||||
dict[e.NewItem.Key] = (e.NewItem.Value, v);
|
|
||||||
filter.InvokeOnAdd(new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value), v, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var v = selector(e.NewItem);
|
||||||
|
dict[e.NewItem.Key] = (e.NewItem.Value, v);
|
||||||
|
filter.InvokeOnAdd(new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value), v, e);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Reset:
|
case NotifyCollectionChangedAction.Reset:
|
||||||
|
{
|
||||||
|
if (!filter.IsNullFilter())
|
||||||
{
|
{
|
||||||
if (!filter.IsNullFilter())
|
foreach (var item in dict)
|
||||||
{
|
{
|
||||||
foreach (var item in dict)
|
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2), e);
|
||||||
{
|
|
||||||
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dict.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dict.Clear();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Move: // ObservableDictionary have no Move operation.
|
case NotifyCollectionChangedAction.Move: // ObservableDictionary have no Move operation.
|
||||||
default:
|
default:
|
||||||
@ -168,4 +177,4 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -51,14 +51,21 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var (_, (value, view)) in dict)
|
foreach (var (_, (value, view)) in dict)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd((value, view), NotifyCollectionChangedEventArgs<T>.Add(value, -1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,14 +53,23 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var (value, view) in list)
|
for (var i = 0; i < list.Count; i++)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
var (value, view) = list[i];
|
||||||
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
var eventArgs = NotifyCollectionChangedEventArgs<T>.Add(value, i);
|
||||||
|
filter.InvokeOnAdd(value, view, eventArgs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,24 +202,24 @@ namespace ObservableCollections
|
|||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Replace:
|
case NotifyCollectionChangedAction.Replace:
|
||||||
// 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];
|
var oldItem = list[e.NewStartingIndex];
|
||||||
list[e.NewStartingIndex] = v;
|
list[e.NewStartingIndex] = v;
|
||||||
|
|
||||||
filter.InvokeOnRemove(oldItem, e);
|
filter.InvokeOnRemove(oldItem, e);
|
||||||
filter.InvokeOnAdd(v, e);
|
filter.InvokeOnAdd(v, e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NotifyCollectionChangedAction.Move:
|
case NotifyCollectionChangedAction.Move:
|
||||||
{
|
{
|
||||||
var removeItem = list[e.OldStartingIndex];
|
var removeItem = list[e.OldStartingIndex];
|
||||||
list.RemoveAt(e.OldStartingIndex);
|
list.RemoveAt(e.OldStartingIndex);
|
||||||
list.Insert(e.NewStartingIndex, removeItem);
|
list.Insert(e.NewStartingIndex, removeItem);
|
||||||
|
|
||||||
filter.InvokeOnMove(removeItem, e);
|
filter.InvokeOnMove(removeItem, e);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Reset:
|
case NotifyCollectionChangedAction.Reset:
|
||||||
if (!filter.IsNullFilter())
|
if (!filter.IsNullFilter())
|
||||||
|
@ -53,14 +53,23 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
|
var i = 0;
|
||||||
foreach (var (value, view) in queue)
|
foreach (var (value, view) in queue)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,14 +54,22 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
foreach (var (value, view) in ringBuffer)
|
for (var i = 0; i < ringBuffer.Count; i++)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
var (value, view) = ringBuffer[i];
|
||||||
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,14 +53,23 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
|
var i = 0;
|
||||||
foreach (var (value, view) in stack)
|
foreach (var (value, view) in stack)
|
||||||
{
|
{
|
||||||
filter.InvokeOnAttach(value, view);
|
if (invokeAddEventForCurrentElements)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,5 +154,36 @@ namespace ObservableCollections.Tests
|
|||||||
.OrderBy(x => x.Value)
|
.OrderBy(x => x.Value)
|
||||||
.Should().Equal((ChangedKind.Remove, -1090), (ChangedKind.Remove, -100), (ChangedKind.Remove, -53), (ChangedKind.Remove, -40), (ChangedKind.Remove, -34));
|
.Should().Equal((ChangedKind.Remove, -1090), (ChangedKind.Remove, -100), (ChangedKind.Remove, -53), (ChangedKind.Remove, -40), (ChangedKind.Remove, -34));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterAndInvokeAddEvent()
|
||||||
|
{
|
||||||
|
var dict = new ObservableDictionary<int, int>();
|
||||||
|
var view1 = dict.CreateView(x => new ViewContainer<int>(x.Value));
|
||||||
|
var filter1 = new TestFilter2<int>((x, v) => x.Value % 2 == 0);
|
||||||
|
|
||||||
|
dict.Add(10, -12); // 0
|
||||||
|
dict.Add(50, -53); // 1
|
||||||
|
dict.Add(30, -34); // 2
|
||||||
|
dict.Add(20, -25); // 3
|
||||||
|
dict.Add(40, -40); // 4
|
||||||
|
|
||||||
|
view1.AttachFilter(filter1, true);
|
||||||
|
|
||||||
|
filter1.CalledOnCollectionChanged.Count.Should().Be(5);
|
||||||
|
filter1.CalledOnCollectionChanged[0].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter1.CalledOnCollectionChanged[0].value.Key.Should().Be(10);
|
||||||
|
filter1.CalledOnCollectionChanged[1].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter1.CalledOnCollectionChanged[1].value.Key.Should().Be(50);
|
||||||
|
filter1.CalledOnCollectionChanged[2].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter1.CalledOnCollectionChanged[2].value.Key.Should().Be(30);
|
||||||
|
filter1.CalledOnCollectionChanged[3].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter1.CalledOnCollectionChanged[3].value.Key.Should().Be(20);
|
||||||
|
filter1.CalledOnCollectionChanged[4].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter1.CalledOnCollectionChanged[4].value.Key.Should().Be(40);
|
||||||
|
|
||||||
|
filter1.CalledWhenTrue.Count.Should().Be(3);
|
||||||
|
filter1.CalledWhenFalse.Count.Should().Be(2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,5 +76,35 @@ namespace ObservableCollections.Tests
|
|||||||
set.RemoveRange(new[] { 50, 30 });
|
set.RemoveRange(new[] { 50, 30 });
|
||||||
filter.CalledOnCollectionChanged.Select(x => (x.changedKind, x.value)).Should().Equal((ChangedKind.Remove, 10), (ChangedKind.Remove, 50), (ChangedKind.Remove, 30));
|
filter.CalledOnCollectionChanged.Select(x => (x.changedKind, x.value)).Should().Equal((ChangedKind.Remove, 10), (ChangedKind.Remove, 50), (ChangedKind.Remove, 30));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterAndInvokeAddEvent()
|
||||||
|
{
|
||||||
|
var set = new ObservableHashSet<int>();
|
||||||
|
var view = set.CreateView(x => new ViewContainer<int>(x));
|
||||||
|
var filter = new TestFilter<int>((x, v) => x % 3 == 0);
|
||||||
|
|
||||||
|
set.Add(10);
|
||||||
|
set.Add(50);
|
||||||
|
set.Add(30);
|
||||||
|
set.Add(20);
|
||||||
|
set.Add(40);
|
||||||
|
|
||||||
|
view.AttachFilter(filter, true);
|
||||||
|
filter.CalledOnCollectionChanged.Count.Should().Be(5);
|
||||||
|
filter.CalledOnCollectionChanged[0].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[0].value.Should().Be(10);
|
||||||
|
filter.CalledOnCollectionChanged[1].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[1].value.Should().Be(50);
|
||||||
|
filter.CalledOnCollectionChanged[2].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[2].value.Should().Be(30);
|
||||||
|
filter.CalledOnCollectionChanged[3].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[3].value.Should().Be(20);
|
||||||
|
filter.CalledOnCollectionChanged[4].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[4].value.Should().Be(40);
|
||||||
|
|
||||||
|
filter.CalledWhenTrue.Count.Should().Be(1);
|
||||||
|
filter.CalledWhenFalse.Count.Should().Be(4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,5 +218,28 @@ namespace ObservableCollections.Tests
|
|||||||
filter2.CalledOnCollectionChanged.Select(x => (x.changedKind, x.value)).Should().Equal((ChangedKind.Remove, 21), (ChangedKind.Remove, 30), (ChangedKind.Remove, 44), (ChangedKind.Remove, 45), (ChangedKind.Remove, 66), (ChangedKind.Remove, 90), (ChangedKind.Remove, 100), (ChangedKind.Remove, 101), (ChangedKind.Remove, 9999));
|
filter2.CalledOnCollectionChanged.Select(x => (x.changedKind, x.value)).Should().Equal((ChangedKind.Remove, 21), (ChangedKind.Remove, 30), (ChangedKind.Remove, 44), (ChangedKind.Remove, 45), (ChangedKind.Remove, 66), (ChangedKind.Remove, 90), (ChangedKind.Remove, 100), (ChangedKind.Remove, 101), (ChangedKind.Remove, 9999));
|
||||||
filter3.CalledOnCollectionChanged.Select(x => (x.changedKind, x.value)).Should().Equal((ChangedKind.Remove, 21), (ChangedKind.Remove, 30), (ChangedKind.Remove, 44), (ChangedKind.Remove, 45), (ChangedKind.Remove, 66), (ChangedKind.Remove, 90), (ChangedKind.Remove, 100), (ChangedKind.Remove, 101), (ChangedKind.Remove, 9999));
|
filter3.CalledOnCollectionChanged.Select(x => (x.changedKind, x.value)).Should().Equal((ChangedKind.Remove, 21), (ChangedKind.Remove, 30), (ChangedKind.Remove, 44), (ChangedKind.Remove, 45), (ChangedKind.Remove, 66), (ChangedKind.Remove, 90), (ChangedKind.Remove, 100), (ChangedKind.Remove, 101), (ChangedKind.Remove, 9999));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterAndInvokeAddEvent()
|
||||||
|
{
|
||||||
|
var list = new ObservableList<int>();
|
||||||
|
var view1 = list.CreateView(x => new ViewContainer<int>(x));
|
||||||
|
list.AddRange(new[] { 10, 21, 30, 44 });
|
||||||
|
|
||||||
|
var filter1 = new TestFilter<int>((x, v) => x % 2 == 0);
|
||||||
|
view1.AttachFilter(filter1, true);
|
||||||
|
|
||||||
|
filter1.CalledOnCollectionChanged[0].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter1.CalledOnCollectionChanged[0].value.Should().Be(10);
|
||||||
|
filter1.CalledOnCollectionChanged[1].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter1.CalledOnCollectionChanged[1].value.Should().Be(21);
|
||||||
|
filter1.CalledOnCollectionChanged[2].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter1.CalledOnCollectionChanged[2].value.Should().Be(30);
|
||||||
|
filter1.CalledOnCollectionChanged[3].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter1.CalledOnCollectionChanged[3].value.Should().Be(44);
|
||||||
|
|
||||||
|
filter1.CalledWhenTrue.Count.Should().Be(3);
|
||||||
|
filter1.CalledWhenFalse.Count.Should().Be(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -80,5 +80,36 @@ namespace ObservableCollections.Tests
|
|||||||
queue.DequeueRange(2);
|
queue.DequeueRange(2);
|
||||||
filter.CalledOnCollectionChanged.Select(x => (x.changedKind, x.value)).Should().Equal((ChangedKind.Remove, 10), (ChangedKind.Remove, 50), (ChangedKind.Remove, 30));
|
filter.CalledOnCollectionChanged.Select(x => (x.changedKind, x.value)).Should().Equal((ChangedKind.Remove, 10), (ChangedKind.Remove, 50), (ChangedKind.Remove, 30));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterAndInvokeAddEvent()
|
||||||
|
{
|
||||||
|
var queue = new ObservableQueue<int>();
|
||||||
|
var view = queue.CreateView(x => new ViewContainer<int>(x));
|
||||||
|
var filter = new TestFilter<int>((x, v) => x % 3 == 0);
|
||||||
|
|
||||||
|
queue.Enqueue(10);
|
||||||
|
queue.Enqueue(50);
|
||||||
|
queue.Enqueue(30);
|
||||||
|
queue.Enqueue(20);
|
||||||
|
queue.Enqueue(40);
|
||||||
|
|
||||||
|
view.AttachFilter(filter, true);
|
||||||
|
|
||||||
|
filter.CalledOnCollectionChanged.Count.Should().Be(5);
|
||||||
|
filter.CalledOnCollectionChanged[0].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[0].value.Should().Be(10);
|
||||||
|
filter.CalledOnCollectionChanged[1].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[1].value.Should().Be(50);
|
||||||
|
filter.CalledOnCollectionChanged[2].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[2].value.Should().Be(30);
|
||||||
|
filter.CalledOnCollectionChanged[3].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[3].value.Should().Be(20);
|
||||||
|
filter.CalledOnCollectionChanged[4].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[4].value.Should().Be(40);
|
||||||
|
|
||||||
|
filter.CalledWhenTrue.Count.Should().Be(1);
|
||||||
|
filter.CalledWhenFalse.Count.Should().Be(4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,5 +80,36 @@ namespace ObservableCollections.Tests
|
|||||||
stack.PopRange(2);
|
stack.PopRange(2);
|
||||||
filter.CalledOnCollectionChanged.Select(x => (x.changedKind, x.value)).Should().Equal((ChangedKind.Remove, 98), (ChangedKind.Remove, 33), (ChangedKind.Remove, 40));
|
filter.CalledOnCollectionChanged.Select(x => (x.changedKind, x.value)).Should().Equal((ChangedKind.Remove, 98), (ChangedKind.Remove, 33), (ChangedKind.Remove, 40));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterAndInvokeAddEvent()
|
||||||
|
{
|
||||||
|
var stack = new ObservableStack<int>();
|
||||||
|
var view = stack.CreateView(x => new ViewContainer<int>(x));
|
||||||
|
var filter = new TestFilter<int>((x, v) => x % 3 == 0);
|
||||||
|
|
||||||
|
stack.Push(10);
|
||||||
|
stack.Push(50);
|
||||||
|
stack.Push(30);
|
||||||
|
stack.Push(20);
|
||||||
|
stack.Push(40);
|
||||||
|
|
||||||
|
view.AttachFilter(filter, true);
|
||||||
|
filter.CalledOnCollectionChanged.Count.Should().Be(5);
|
||||||
|
filter.CalledOnCollectionChanged[4].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[4].value.Should().Be(10);
|
||||||
|
filter.CalledOnCollectionChanged[3].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[3].value.Should().Be(50);
|
||||||
|
filter.CalledOnCollectionChanged[2].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[2].value.Should().Be(30);
|
||||||
|
filter.CalledOnCollectionChanged[1].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[1].value.Should().Be(20);
|
||||||
|
filter.CalledOnCollectionChanged[0].changedKind.Should().Be(ChangedKind.Add);
|
||||||
|
filter.CalledOnCollectionChanged[0].value.Should().Be(40);
|
||||||
|
|
||||||
|
filter.CalledWhenTrue.Count.Should().Be(1);
|
||||||
|
filter.CalledWhenFalse.Count.Should().Be(4);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user