This commit is contained in:
neuecc 2024-08-27 23:28:30 +09:00
parent 295cef5ae5
commit 5b3eb80158
26 changed files with 269 additions and 1783 deletions

View File

@ -33,13 +33,13 @@ var viewModels = models.CreateView(x => new ViewModel
Value = "@" + x
});
viewModels.AttachFilter(new HogeFilter(), true);
viewModels.AttachFilter(new HogeFilter());
models.Add(100);
foreach (var (x, xs) in viewModels)
foreach (var x in viewModels)
{
System.Console.WriteLine(xs.Value);
System.Console.WriteLine(x);
}
class ViewModel
@ -48,23 +48,13 @@ class ViewModel
public string Value { get; set; } = default!;
}
class HogeFilter : ISynchronizedViewFilter<int, ViewModel>
class HogeFilter : ISynchronizedViewFilter<int>
{
public bool IsMatch(int value, ViewModel view)
public bool IsMatch(int value)
{
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(in SynchronizedViewChangedEventArgs<int, ViewModel> eventArgs)
{
switch (eventArgs.Action)

View File

@ -1,59 +0,0 @@
#nullable disable
using ObservableCollections.Internal;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace ObservableCollections
{
public sealed class FreezedDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>, IFreezedCollection<KeyValuePair<TKey, TValue>>
where TKey : notnull
{
readonly IReadOnlyDictionary<TKey, TValue> dictionary;
public FreezedDictionary(IReadOnlyDictionary<TKey, TValue> dictionary)
{
this.dictionary = dictionary;
}
public TValue this[TKey key] => dictionary[key];
public IEnumerable<TKey> Keys => dictionary.Keys;
public IEnumerable<TValue> Values => dictionary.Values;
public int Count => dictionary.Count;
public bool ContainsKey(TKey key)
{
return dictionary.ContainsKey(key);
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return dictionary.GetEnumerator();
}
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
{
return dictionary.TryGetValue(key, out value);
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)dictionary).GetEnumerator();
}
public ISynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform, bool reverse = false)
{
return new FreezedView<KeyValuePair<TKey, TValue>, TView>(dictionary, transform, reverse);
}
public ISortableSynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateSortableView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform)
{
return new FreezedSortableView<KeyValuePair<TKey, TValue>, TView>(dictionary, transform);
}
}
}

View File

@ -1,61 +0,0 @@
using ObservableCollections.Internal;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace ObservableCollections
{
public sealed class FreezedList<T> : IReadOnlyList<T>, IFreezedCollection<T>
{
readonly IReadOnlyList<T> list;
public T this[int index]
{
get
{
return list[index];
}
}
public int Count
{
get
{
return list.Count;
}
}
public bool IsReadOnly => true;
public FreezedList(IReadOnlyList<T> list)
{
this.list = list;
}
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false)
{
return new FreezedView<T, TView>(list, transform, reverse);
}
public ISortableSynchronizedView<T, TView> CreateSortableView<TView>(Func<T, TView> transform)
{
return new FreezedSortableView<T, TView>(list, transform);
}
public bool Contains(T item)
{
return list.Contains(item);
}
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

View File

@ -1,4 +1,3 @@
using ObservableCollections.Internal;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
@ -7,6 +6,7 @@ using System.ComponentModel;
namespace ObservableCollections
{
public delegate void NotifyCollectionChangedEventHandler<T>(in NotifyCollectionChangedEventArgs<T> e);
public delegate void NotifyViewChangedEventHandler<T, TView>(in SynchronizedViewChangedEventArgs<T, TView> e);
public interface IObservableCollection<T> : IReadOnlyCollection<T>
{
@ -25,12 +25,6 @@ namespace ObservableCollections
{
}
public interface IFreezedCollection<T>
{
ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false);
ISortableSynchronizedView<T, TView> CreateSortableView<TView>(Func<T, TView> transform);
}
public interface ISynchronizedView<T, TView> : IReadOnlyCollection<TView>, IDisposable
{
object SyncRoot { get; }
@ -39,7 +33,7 @@ namespace ObservableCollections
IEnumerable<(T Value, TView View)> Unfiltered { get; }
int UnfilteredCount { get; }
event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
void AttachFilter(ISynchronizedViewFilter<T> filter);
@ -49,17 +43,6 @@ namespace ObservableCollections
INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher);
}
public interface ISortableSynchronizedView<T, TView> : ISynchronizedView<T, TView>
{
void Sort(IComparer<T> comparer);
void Sort(IComparer<TView> viewComparer);
}
// will be implemented in the future?
//public interface IGroupedSynchoronizedView<T, TKey, TView> : ILookup<TKey, (T, TView)>, ISynchronizedView<T, TView>
//{
//}
public interface ISynchronizedViewList<out TView> : IReadOnlyList<TView>, IDisposable
{
}
@ -67,72 +50,4 @@ namespace ObservableCollections
public interface INotifyCollectionChangedSynchronizedView<out TView> : IReadOnlyCollection<TView>, INotifyCollectionChanged, INotifyPropertyChanged, IDisposable
{
}
public static class ObservableCollectionsExtensions
{
public static ISynchronizedView<T, TView> CreateSortedView<T, TKey, TView>(this IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<T> comparer)
where TKey : notnull
{
return new SortedView<T, TKey, TView>(source, identitySelector, transform, comparer);
}
public static ISynchronizedView<T, TView> CreateSortedView<T, TKey, TView>(this IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> viewComparer)
where TKey : notnull
{
return new SortedViewViewComparer<T, TKey, TView>(source, identitySelector, transform, viewComparer);
}
public static ISynchronizedView<T, TView> CreateSortedView<T, TKey, TView, TCompare>(this IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, Func<T, TCompare> compareSelector, bool ascending = true)
where TKey : notnull
{
return source.CreateSortedView(identitySelector, transform, new AnonymousComparer<T, TCompare>(compareSelector, ascending));
}
public static ISortableSynchronizedView<T, TView> CreateSortableView<T, TView>(this IFreezedCollection<T> source, Func<T, TView> transform, IComparer<T> initialSort)
{
var view = source.CreateSortableView(transform);
view.Sort(initialSort);
return view;
}
public static ISortableSynchronizedView<T, TView> CreateSortableView<T, TView>(this IFreezedCollection<T> source, Func<T, TView> transform, IComparer<TView> initialViewSort)
{
var view = source.CreateSortableView(transform);
view.Sort(initialViewSort);
return view;
}
public static ISortableSynchronizedView<T, TView> CreateSortableView<T, TView, TCompare>(this IFreezedCollection<T> source, Func<T, TView> transform, Func<T, TCompare> initialCompareSelector, bool ascending = true)
{
var view = source.CreateSortableView(transform);
view.Sort(initialCompareSelector, ascending);
return view;
}
public static void Sort<T, TView, TCompare>(this ISortableSynchronizedView<T, TView> source, Func<T, TCompare> compareSelector, bool ascending = true)
{
source.Sort(new AnonymousComparer<T, TCompare>(compareSelector, ascending));
}
class AnonymousComparer<T, TCompare> : IComparer<T>
{
readonly Func<T, TCompare> selector;
readonly int f;
public AnonymousComparer(Func<T, TCompare> selector, bool ascending)
{
this.selector = selector;
this.f = ascending ? 1 : -1;
}
public int Compare(T? x, T? y)
{
if (x == null && y == null) return 0;
if (x == null) return 1 * f;
if (y == null) return -1 * f;
return Comparer<TCompare>.Default.Compare(selector(x), selector(y)) * f;
}
}
}
}

View File

@ -3,8 +3,8 @@ using System.Collections.Specialized;
namespace ObservableCollections
{
public readonly struct SynchronizedViewChangedEventArgs<T, TView>(
NotifyViewChangedAction action,
public readonly ref struct SynchronizedViewChangedEventArgs<T, TView>(
NotifyCollectionChangedAction action,
T newValue = default!,
T oldValue = default!,
TView newView = default!,
@ -12,7 +12,7 @@ namespace ObservableCollections
int newViewIndex = -1,
int oldViewIndex = -1)
{
public readonly NotifyViewChangedAction Action = action;
public readonly NotifyCollectionChangedAction Action = action;
public readonly T NewValue = newValue;
public readonly T OldValue = oldValue;
public readonly TView NewView = newView;
@ -21,16 +21,6 @@ namespace ObservableCollections
public readonly int OldViewIndex = oldViewIndex;
}
public enum NotifyViewChangedAction
{
Add = 0,
Remove = 1,
Replace = 2,
Move = 3,
Reset = 4,
FilterReset = 5,
}
public interface ISynchronizedViewFilter<T>
{
bool IsMatch(T value);
@ -60,12 +50,12 @@ namespace ObservableCollections
return filter == SynchronizedViewFilter<T>.Null;
}
internal static void InvokeOnAdd<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, Action<SynchronizedViewChangedEventArgs<T, TView>>? ev, (T value, TView view) value, int index)
internal static void InvokeOnAdd<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, (T value, TView view) value, int index)
{
InvokeOnAdd(collection, ref filteredCount, ev, value.value, value.view, index);
}
internal static void InvokeOnAdd<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, Action<SynchronizedViewChangedEventArgs<T, TView>>? ev, T value, TView view, int index)
internal static void InvokeOnAdd<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, T value, TView view, int index)
{
var isMatch = collection.Filter.IsMatch(value);
if (isMatch)
@ -73,17 +63,17 @@ namespace ObservableCollections
filteredCount++;
if (ev != null)
{
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.Add, newValue: value, newView: view, newViewIndex: index));
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, newValue: value, newView: view, newViewIndex: index));
}
}
}
internal static void InvokeOnRemove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, Action<SynchronizedViewChangedEventArgs<T, TView>>? ev, (T value, TView view) value, int oldIndex)
internal static void InvokeOnRemove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, (T value, TView view) value, int oldIndex)
{
InvokeOnRemove(collection, ref filteredCount, ev, value.value, value.view, oldIndex);
}
internal static void InvokeOnRemove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, Action<SynchronizedViewChangedEventArgs<T, TView>>? ev, T value, TView view, int oldIndex)
internal static void InvokeOnRemove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, T value, TView view, int oldIndex)
{
var isMatch = collection.Filter.IsMatch(value);
if (isMatch)
@ -91,17 +81,17 @@ namespace ObservableCollections
filteredCount--;
if (ev != null)
{
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.Remove, oldValue: value, oldView: view, oldViewIndex: oldIndex));
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, oldValue: value, oldView: view, oldViewIndex: oldIndex));
}
}
}
internal static void InvokeOnMove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, Action<SynchronizedViewChangedEventArgs<T, TView>>? ev, (T value, TView view) value, int index, int oldIndex)
internal static void InvokeOnMove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, (T value, TView view) value, int index, int oldIndex)
{
InvokeOnMove(collection, ref filteredCount, ev, value.value, value.view, index, oldIndex);
}
internal static void InvokeOnMove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, Action<SynchronizedViewChangedEventArgs<T, TView>>? ev, T value, TView view, int index, int oldIndex)
internal static void InvokeOnMove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, T value, TView view, int index, int oldIndex)
{
if (ev != null)
{
@ -109,17 +99,17 @@ namespace ObservableCollections
var isMatch = collection.Filter.IsMatch(value);
if (isMatch)
{
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.Move, newValue: value, newView: view, newViewIndex: index, oldViewIndex: oldIndex));
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Move, newValue: value, newView: view, newViewIndex: index, oldViewIndex: oldIndex));
}
}
}
internal static void InvokeOnReplace<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, Action<SynchronizedViewChangedEventArgs<T, TView>>? ev, (T value, TView view) value, (T value, TView view) oldValue, int index, int oldIndex = -1)
internal static void InvokeOnReplace<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, (T value, TView view) value, (T value, TView view) oldValue, int index, int oldIndex = -1)
{
InvokeOnReplace(collection, ref filteredCount, ev, value.value, value.view, oldValue.value, oldValue.view, index, oldIndex);
}
internal static void InvokeOnReplace<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, Action<SynchronizedViewChangedEventArgs<T, TView>>? ev, T value, TView view, T oldValue, TView oldView, int index, int oldIndex = -1)
internal static void InvokeOnReplace<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, T value, TView view, T oldValue, TView oldView, int index, int oldIndex = -1)
{
var oldMatched = collection.Filter.IsMatch(oldValue);
var newMatched = collection.Filter.IsMatch(value);
@ -129,7 +119,7 @@ namespace ObservableCollections
{
if (ev != null)
{
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.Replace, newValue: value, newView: view, oldValue: oldValue, oldView: oldView, newViewIndex: index, oldViewIndex: oldIndex >= 0 ? oldIndex : index));
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Replace, newValue: value, newView: view, oldValue: oldValue, oldView: oldView, newViewIndex: index, oldViewIndex: oldIndex >= 0 ? oldIndex : index));
}
}
else if (oldMatched)
@ -138,7 +128,7 @@ namespace ObservableCollections
filteredCount--;
if (ev != null)
{
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.Remove, oldValue: value, oldView: view, oldViewIndex: oldIndex));
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, oldValue: value, oldView: view, oldViewIndex: oldIndex));
}
}
@ -148,17 +138,17 @@ namespace ObservableCollections
filteredCount++;
if (ev != null)
{
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.Add, newValue: value, newView: view, newViewIndex: index));
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, newValue: value, newView: view, newViewIndex: index));
}
}
}
internal static void InvokeOnReset<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, Action<SynchronizedViewChangedEventArgs<T, TView>>? ev)
internal static void InvokeOnReset<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev)
{
filteredCount = 0;
if (ev != null)
{
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.Reset));
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset));
}
}
}

View File

@ -1,264 +0,0 @@
#pragma warning disable CS0067
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
namespace ObservableCollections.Internal
{
internal sealed class FreezedView<T, TView> : ISynchronizedView<T, TView>
{
readonly bool reverse;
readonly List<(T, TView)> list;
ISynchronizedViewFilter<T, TView> filter;
public ISynchronizedViewFilter<T, TView> CurrentFilter
{
get { lock (SyncRoot) return filter; }
}
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
public object SyncRoot { get; } = new object();
public FreezedView(IEnumerable<T> source, Func<T, TView> selector, bool reverse)
{
this.reverse = reverse;
this.filter = SynchronizedViewFilter<T, TView>.Null;
this.list = source.Select(x => (x, selector(x))).ToList();
}
public int Count
{
get
{
lock (SyncRoot)
{
return list.Count;
}
}
}
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
{
lock (SyncRoot)
{
this.filter = filter;
for (var i = 0; i < list.Count; i++)
{
var (value, view) = list[i];
if (invokeAddEventForCurrentElements)
{
filter.InvokeOnAdd(value, view, i);
}
else
{
filter.InvokeOnAttach(value, view);
}
}
}
}
public void ResetFilter(Action<T, TView>? resetAction)
{
lock (SyncRoot)
{
this.filter = SynchronizedViewFilter<T, TView>.Null;
if (resetAction != null)
{
foreach (var (item, view) in list)
{
resetAction(item, view);
}
}
}
}
public IEnumerator<(T, TView)> GetEnumerator()
{
lock (SyncRoot)
{
if (!reverse)
{
foreach (var item in list)
{
if (filter.IsMatch(item.Item1, item.Item2))
{
yield return item;
}
}
}
else
{
foreach (var item in list.AsEnumerable().Reverse())
{
if (filter.IsMatch(item.Item1, item.Item2))
{
yield return item;
}
}
}
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public void Dispose()
{
}
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
{
return new NotifyCollectionChangedSynchronizedView<T, TView>(this, null);
}
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher)
{
return new NotifyCollectionChangedSynchronizedView<T, TView>(this, collectionEventDispatcher);
}
}
internal sealed class FreezedSortableView<T, TView> : ISortableSynchronizedView<T, TView>
{
readonly (T, TView)[] array;
ISynchronizedViewFilter<T, TView> filter;
public ISynchronizedViewFilter<T, TView> CurrentFilter
{
get { lock (SyncRoot) return filter; }
}
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
public object SyncRoot { get; } = new object();
public FreezedSortableView(IEnumerable<T> source, Func<T, TView> selector)
{
this.filter = SynchronizedViewFilter<T, TView>.Null;
this.array = source.Select(x => (x, selector(x))).ToArray();
}
public int Count
{
get
{
lock (SyncRoot)
{
return array.Length;
}
}
}
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
{
lock (SyncRoot)
{
this.filter = filter;
for (var i = 0; i < array.Length; i++)
{
var (value, view) = array[i];
if (invokeAddEventForCurrentElements)
{
filter.InvokeOnAdd(value, view, i);
}
else
{
filter.InvokeOnAttach(value, view);
}
}
}
}
public void ResetFilter(Action<T, TView>? resetAction)
{
lock (SyncRoot)
{
this.filter = SynchronizedViewFilter<T, TView>.Null;
if (resetAction != null)
{
foreach (var (item, view) in array)
{
resetAction(item, view);
}
}
}
}
public IEnumerator<(T, TView)> GetEnumerator()
{
lock (SyncRoot)
{
foreach (var item in array)
{
if (filter.IsMatch(item.Item1, item.Item2))
{
yield return item;
}
}
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public void Dispose()
{
}
public void Sort(IComparer<T> comparer)
{
Array.Sort(array, new TComparer(comparer));
}
public void Sort(IComparer<TView> viewComparer)
{
Array.Sort(array, new TViewComparer(viewComparer));
}
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
{
return new NotifyCollectionChangedSynchronizedView<T, TView>(this, null);
}
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher)
{
return new NotifyCollectionChangedSynchronizedView<T, TView>(this, collectionEventDispatcher);
}
class TComparer : IComparer<(T, TView)>
{
readonly IComparer<T> comparer;
public TComparer(IComparer<T> comparer)
{
this.comparer = comparer;
}
public int Compare((T, TView) x, (T, TView) y)
{
return comparer.Compare(x.Item1, y.Item1);
}
}
class TViewComparer : IComparer<(T, TView)>
{
readonly IComparer<TView> comparer;
public TViewComparer(IComparer<TView> comparer)
{
this.comparer = comparer;
}
public int Compare((T, TView) x, (T, TView) y)
{
return comparer.Compare(x.Item2, y.Item2);
}
}
}
}

View File

@ -1,259 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
namespace ObservableCollections.Internal
{
internal class SortedView<T, TKey, TView> : ISynchronizedView<T, TView>
where TKey : notnull
{
public ISynchronizedViewFilter<T, TView> CurrentFilter
{
get { lock (SyncRoot) return filter; }
}
readonly IObservableCollection<T> source;
readonly Func<T, TView> transform;
readonly Func<T, TKey> identitySelector;
readonly SortedList<(T Value, TKey Key), (T Value, TView View)> list;
ISynchronizedViewFilter<T, TView> filter;
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public object SyncRoot { get; } = new object();
public SortedView(IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<T> comparer)
{
this.source = source;
this.identitySelector = identitySelector;
this.transform = transform;
this.filter = SynchronizedViewFilter<T, TView>.Null;
lock (source.SyncRoot)
{
var dict = new Dictionary<(T, TKey), (T, TView)>(source.Count);
foreach (var v in source)
{
dict.Add((v, identitySelector(v)), (v, transform(v)));
}
this.list = new SortedList<(T Value, TKey Key), (T Value, TView View)>(dict, new Comparer(comparer));
this.source.CollectionChanged += SourceCollectionChanged;
}
}
public int Count
{
get
{
lock (SyncRoot)
{
return list.Count;
}
}
}
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
{
lock (SyncRoot)
{
this.filter = filter;
var i = 0;
foreach (var (_, (value, view)) in list)
{
if (invokeAddEventForCurrentElements)
{
filter.InvokeOnAdd(value, view, i++);
}
else
{
filter.InvokeOnAttach(value, view);
}
}
}
}
public void ResetFilter(Action<T, TView>? resetAction)
{
lock (SyncRoot)
{
this.filter = SynchronizedViewFilter<T, TView>.Null;
if (resetAction != null)
{
foreach (var (_, (value, view)) in list)
{
resetAction(value, view);
}
}
}
}
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
{
lock (SyncRoot)
{
return new NotifyCollectionChangedSynchronizedView<T, TView>(this, null);
}
}
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher)
{
lock (SyncRoot)
{
return new NotifyCollectionChangedSynchronizedView<T, TView>(this, collectionEventDispatcher);
}
}
public IEnumerator<(T, TView)> GetEnumerator()
{
lock (SyncRoot)
{
foreach (var item in list)
{
if (filter.IsMatch(item.Value.Value, item.Value.View))
{
yield return item.Value;
}
}
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public void Dispose()
{
this.source.CollectionChanged -= SourceCollectionChanged;
}
private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
{
lock (SyncRoot)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
{
// Add, Insert
if (e.IsSingleItem)
{
var value = e.NewItem;
var view = transform(value);
var id = identitySelector(value);
list.Add((value, id), (value, view));
var index = list.IndexOfKey((value, id));
filter.InvokeOnAdd(value, view, index);
}
else
{
foreach (var value in e.NewItems)
{
var view = transform(value);
var id = identitySelector(value);
list.Add((value, id), (value, view));
var index = list.IndexOfKey((value, id));
filter.InvokeOnAdd(value, view, index);
}
}
}
break;
case NotifyCollectionChangedAction.Remove:
{
if (e.IsSingleItem)
{
var value = e.OldItem;
var id = identitySelector(value);
var key = (value, id);
if (list.TryGetValue(key, out var v))
{
var index = list.IndexOfKey(key);
list.RemoveAt(index);
filter.InvokeOnRemove(v.Value, v.View, index);
}
}
else
{
foreach (var value in e.OldItems)
{
var id = identitySelector(value);
var key = (value, id);
if (list.TryGetValue(key, out var v))
{
var index = list.IndexOfKey((value, id));
list.RemoveAt(index);
filter.InvokeOnRemove(v.Value, v.View, index);
}
}
}
}
break;
case NotifyCollectionChangedAction.Replace:
// ReplaceRange is not supported in all ObservableCollections collections
// Replace is remove old item and insert new item.
{
var oldValue = e.OldItem;
var oldKey = (oldValue, identitySelector(oldValue));
var oldIndex = -1;
if (list.TryGetValue(oldKey, out var o))
{
oldIndex = list.IndexOfKey(oldKey);
list.RemoveAt(oldIndex);
}
var value = e.NewItem;
var view = transform(value);
var id = identitySelector(value);
list.Add((value, id), (value, view));
var newIndex = list.IndexOfKey((value, id));
filter.InvokeOnReplace((value, view), o, newIndex, oldIndex: oldIndex);
}
break;
case NotifyCollectionChangedAction.Move:
{
// Move(index change) does not affect sorted list.
var oldValue = e.OldItem;
var oldKey = (oldValue, identitySelector(oldValue));
if (list.TryGetValue(oldKey, out var v))
{
var index = list.IndexOfKey(oldKey);
filter.InvokeOnMove(v, index, index);
}
}
break;
case NotifyCollectionChangedAction.Reset:
list.Clear();
filter.InvokeOnReset();
break;
default:
break;
}
RoutingCollectionChanged?.Invoke(e);
CollectionStateChanged?.Invoke(e.Action);
}
}
sealed class Comparer : IComparer<(T value, TKey id)>
{
readonly IComparer<T> comparer;
public Comparer(IComparer<T> comparer)
{
this.comparer = comparer;
}
public int Compare((T value, TKey id) x, (T value, TKey id) y)
{
var compare = comparer.Compare(x.value, y.value);
if (compare == 0)
{
compare = Comparer<TKey>.Default.Compare(x.id, y.id);
}
return compare;
}
}
}
}

View File

@ -1,278 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
namespace ObservableCollections.Internal
{
internal class SortedViewViewComparer<T, TKey, TView> : ISynchronizedView<T, TView>
where TKey : notnull
{
readonly IObservableCollection<T> source;
readonly Func<T, TView> transform;
readonly Func<T, TKey> identitySelector;
readonly Dictionary<TKey, TView> viewMap; // view-map needs to use in remove.
readonly SortedList<(TView View, TKey Key), (T Value, TView View)> list;
ISynchronizedViewFilter<T, TView> filter;
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public object SyncRoot { get; } = new object();
public ISynchronizedViewFilter<T, TView> CurrentFilter
{
get { lock (SyncRoot) return filter; }
}
public SortedViewViewComparer(IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> comparer)
{
this.source = source;
this.identitySelector = identitySelector;
this.transform = transform;
this.filter = SynchronizedViewFilter<T, TView>.Null;
lock (source.SyncRoot)
{
var dict = new Dictionary<(TView, TKey), (T, TView)>(source.Count);
this.viewMap = new Dictionary<TKey, TView>();
foreach (var value in source)
{
var view = transform(value);
var id = identitySelector(value);
dict.Add((view, id), (value, view));
viewMap.Add(id, view);
}
this.list = new SortedList<(TView View, TKey Key), (T Value, TView View)>(dict, new Comparer(comparer));
this.source.CollectionChanged += SourceCollectionChanged;
}
}
public int Count
{
get
{
lock (SyncRoot)
{
return list.Count;
}
}
}
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
{
lock (SyncRoot)
{
this.filter = filter;
var i = 0;
foreach (var (_, (value, view)) in list)
{
if (invokeAddEventForCurrentElements)
{
filter.InvokeOnAdd(value, view, i++);
}
else
{
filter.InvokeOnAttach(value, view);
}
}
}
}
public void ResetFilter(Action<T, TView>? resetAction)
{
lock (SyncRoot)
{
this.filter = SynchronizedViewFilter<T, TView>.Null;
if (resetAction != null)
{
foreach (var (_, (value, view)) in list)
{
resetAction(value, view);
}
}
}
}
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
{
lock (SyncRoot)
{
return new NotifyCollectionChangedSynchronizedView<T, TView>(this, null);
}
}
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher)
{
lock (SyncRoot)
{
return new NotifyCollectionChangedSynchronizedView<T, TView>(this, collectionEventDispatcher);
}
}
public IEnumerator<(T, TView)> GetEnumerator()
{
lock (SyncRoot)
{
foreach (var item in list)
{
if (filter.IsMatch(item.Value.Value, item.Value.View))
{
yield return item.Value;
}
}
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public void Dispose()
{
this.source.CollectionChanged -= SourceCollectionChanged;
}
private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
{
lock (SyncRoot)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
{
// Add, Insert
if (e.IsSingleItem)
{
var value = e.NewItem;
var view = transform(value);
var id = identitySelector(value);
list.Add((view, id), (value, view));
viewMap.Add(id, view);
var index = list.IndexOfKey((view, id));
filter.InvokeOnAdd(value, view, index);
}
else
{
foreach (var value in e.NewItems)
{
var view = transform(value);
var id = identitySelector(value);
list.Add((view, id), (value, view));
viewMap.Add(id, view);
var index = list.IndexOfKey((view, id));
filter.InvokeOnAdd(value, view, index);
}
}
break;
}
case NotifyCollectionChangedAction.Remove:
{
if (e.IsSingleItem)
{
var value = e.OldItem;
var id = identitySelector(value);
if (viewMap.Remove(id, out var view))
{
var key = (view, id);
if (list.TryGetValue(key, out var v))
{
var index = list.IndexOfKey(key);
list.RemoveAt(index);
filter.InvokeOnRemove(v, index);
}
}
}
else
{
foreach (var value in e.OldItems)
{
var id = identitySelector(value);
if (viewMap.Remove(id, out var view))
{
var key = (view, id);
if (list.TryGetValue(key, out var v))
{
var index = list.IndexOfKey((view, id));
list.RemoveAt(index);
filter.InvokeOnRemove(v, index);
}
}
}
}
break;
}
case NotifyCollectionChangedAction.Replace:
// Replace is remove old item and insert new item.
{
var oldValue = e.OldItem;
var oldId = identitySelector(oldValue);
var oldIndex = -1;
if (viewMap.Remove(oldId, out var oldView))
{
var oldKey = (oldView, oldId);
if (list.TryGetValue(oldKey, out var v))
{
oldIndex = list.IndexOfKey(oldKey);
list.RemoveAt(oldIndex);
}
}
var value = e.NewItem;
var view = transform(value);
var id = identitySelector(value);
list.Add((view, id), (value, view));
viewMap.Add(id, view);
var index = list.IndexOfKey((view, id));
filter.InvokeOnReplace(value, view, oldValue, oldView!, index, oldIndex);
break;
}
case NotifyCollectionChangedAction.Move:
// Move(index change) does not affect soreted dict.
{
var value = e.OldItem;
var id = identitySelector(value);
if (viewMap.TryGetValue(id, out var view))
{
var index = list.IndexOfKey((view, id));
filter.InvokeOnMove(value, view, index, index);
}
break;
}
case NotifyCollectionChangedAction.Reset:
list.Clear();
viewMap.Clear();
filter.InvokeOnReset();
break;
default:
break;
}
RoutingCollectionChanged?.Invoke(e);
CollectionStateChanged?.Invoke(e.Action);
}
}
sealed class Comparer : IComparer<(TView view, TKey id)>
{
readonly IComparer<TView> comparer;
public Comparer(IComparer<TView> comparer)
{
this.comparer = comparer;
}
public int Compare((TView view, TKey id) x, (TView view, TKey id) y)
{
var compare = comparer.Compare(x.view, y.view);
if (compare == 0)
{
compare = Comparer<TKey>.Default.Compare(x.id, y.id);
}
return compare;
}
}
}
}

View File

@ -38,7 +38,7 @@ namespace ObservableCollections
}
public object SyncRoot { get; }
public event Action<SynchronizedViewChangedEventArgs<KeyValuePair<TKey, TValue>, TView>>? ViewChanged;
public event NotifyViewChangedEventHandler<KeyValuePair<TKey, TValue>, TView>? ViewChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public ISynchronizedViewFilter<KeyValuePair<TKey, TValue>> Filter
@ -94,7 +94,7 @@ namespace ObservableCollections
}
}
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<KeyValuePair<TKey, TValue>, TView>(NotifyViewChangedAction.FilterReset));
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<KeyValuePair<TKey, TValue>, TView>(NotifyCollectionChangedAction.Reset));
}
}
@ -104,7 +104,7 @@ namespace ObservableCollections
{
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>>.Null;
this.filteredCount = dict.Count;
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<KeyValuePair<TKey, TValue>, TView>(NotifyViewChangedAction.FilterReset));
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<KeyValuePair<TKey, TValue>, TView>(NotifyCollectionChangedAction.Reset));
}
}

View File

@ -320,9 +320,9 @@ namespace ObservableCollections
return GetEnumerator();
}
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false)
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform)
{
return new ObservableRingBuffer<T>.View<TView>(this, transform, reverse);
return new ObservableRingBuffer<T>.View<TView>(this, transform);
}
}
}

View File

@ -29,7 +29,7 @@ namespace ObservableCollections
ISynchronizedViewFilter<T> filter;
public event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public object SyncRoot { get; }
@ -89,6 +89,7 @@ namespace ObservableCollections
filteredCount++;
}
}
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset));
}
}
@ -98,7 +99,7 @@ namespace ObservableCollections
{
this.filter = SynchronizedViewFilter<T>.Null;
this.filteredCount = dict.Count;
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset));
}
}

View File

@ -46,7 +46,7 @@ namespace ObservableCollections
ISynchronizedViewFilter<T> filter;
public event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public object SyncRoot { get; }
@ -107,7 +107,7 @@ namespace ObservableCollections
}
}
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset));
}
}
@ -117,7 +117,7 @@ namespace ObservableCollections
{
this.filter = SynchronizedViewFilter<T>.Null;
this.filteredCount = list.Count;
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset));
}
}
@ -245,11 +245,12 @@ namespace ObservableCollections
}
else
{
list.RemoveRange(e.OldStartingIndex, e.OldItems.Length); // remove from list first
var len = e.OldStartingIndex + e.OldItems.Length;
for (var i = e.OldStartingIndex; i < len; i++)
{
var v = list[i];
list.RemoveAt(e.OldStartingIndex + i); // should we use RemoveRange?
this.InvokeOnRemove(ref filteredCount, ViewChanged, v, e.OldStartingIndex + i);
}
}

View File

@ -19,13 +19,12 @@ namespace ObservableCollections
{
readonly ObservableQueue<T> source;
readonly Func<T, TView> selector;
readonly bool reverse;
protected readonly Queue<(T, TView)> queue;
int filteredCount;
ISynchronizedViewFilter<T> filter;
public event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public object SyncRoot { get; }
@ -90,7 +89,7 @@ namespace ObservableCollections
filteredCount++;
}
}
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset));
}
}
@ -100,7 +99,7 @@ namespace ObservableCollections
{
this.filter = SynchronizedViewFilter<T>.Null;
this.filteredCount = queue.Count;
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset));
}
}

View File

@ -30,7 +30,7 @@ namespace ObservableCollections
ISynchronizedViewFilter<T> filter;
public event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public object SyncRoot { get; }
@ -91,6 +91,7 @@ namespace ObservableCollections
filteredCount++;
}
}
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset));
}
}
@ -100,7 +101,7 @@ namespace ObservableCollections
{
this.filter = SynchronizedViewFilter<T>.Null;
this.filteredCount = ringBuffer.Count;
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset));
}
}

View File

@ -23,7 +23,7 @@ namespace ObservableCollections
ISynchronizedViewFilter<T> filter;
public event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public object SyncRoot { get; }
@ -88,7 +88,7 @@ namespace ObservableCollections
filteredCount++;
}
}
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset));
}
}
@ -98,7 +98,7 @@ namespace ObservableCollections
{
this.filter = SynchronizedViewFilter<T>.Null;
this.filteredCount = stack.Count;
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset));
}
}

View File

@ -5,7 +5,7 @@ using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
namespace ObservableCollections.Internal
namespace ObservableCollections
{
internal class SynchronizedViewList<T, TView> : ISynchronizedViewList<TView>
{
@ -18,18 +18,18 @@ namespace ObservableCollections.Internal
this.parent = parent;
lock (parent.SyncRoot)
{
this.listView = parent.ToList();
listView = parent.ToList();
parent.ViewChanged += Parent_ViewChanged;
}
}
private void Parent_ViewChanged(SynchronizedViewChangedEventArgs<T, TView> e)
private void Parent_ViewChanged(in SynchronizedViewChangedEventArgs<T, TView> e)
{
lock (gate)
{
switch (e.Action)
{
case NotifyViewChangedAction.Add: // Add or Insert
case NotifyCollectionChangedAction.Add: // Add or Insert
if (e.NewViewIndex == -1)
{
listView.Add(e.NewView);
@ -39,7 +39,7 @@ namespace ObservableCollections.Internal
listView.Insert(e.NewViewIndex, e.NewView);
}
break;
case NotifyViewChangedAction.Remove: // Remove
case NotifyCollectionChangedAction.Remove: // Remove
if (e.OldViewIndex == -1) // can't gurantee correct remove if index is not provided
{
listView.Remove(e.OldView);
@ -49,7 +49,7 @@ namespace ObservableCollections.Internal
listView.RemoveAt(e.OldViewIndex);
}
break;
case NotifyViewChangedAction.Replace: // Indexer
case NotifyCollectionChangedAction.Replace: // Indexer
if (e.NewViewIndex == -1)
{
var index = listView.IndexOf(e.OldView);
@ -61,7 +61,7 @@ namespace ObservableCollections.Internal
}
break;
case NotifyViewChangedAction.Move: //Remove and Insert
case NotifyCollectionChangedAction.Move: //Remove and Insert
if (e.NewViewIndex == -1)
{
// do nothing
@ -72,12 +72,9 @@ namespace ObservableCollections.Internal
listView.Insert(e.NewViewIndex, e.NewView);
}
break;
case NotifyViewChangedAction.Reset: // Clear
case NotifyCollectionChangedAction.Reset: // Clear or drastic changes
listView.Clear();
break;
case NotifyViewChangedAction.FilterReset:
listView.Clear();
foreach (var item in parent)
foreach (var item in parent) // refresh
{
listView.Add(item);
}
@ -163,7 +160,7 @@ namespace ObservableCollections.Internal
switch (args.Action)
{
case NotifyViewChangedAction.Add:
case NotifyCollectionChangedAction.Add:
eventDispatcher.Post(new CollectionEventDispatcherEventArgs(NotifyCollectionChangedAction.Add, args.NewView, args.NewViewIndex)
{
Collection = this,
@ -172,7 +169,7 @@ namespace ObservableCollections.Internal
IsInvokePropertyChanged = true
});
break;
case NotifyViewChangedAction.Remove:
case NotifyCollectionChangedAction.Remove:
eventDispatcher.Post(new CollectionEventDispatcherEventArgs(NotifyCollectionChangedAction.Remove, args.OldView, args.OldViewIndex)
{
Collection = this,
@ -181,7 +178,7 @@ namespace ObservableCollections.Internal
IsInvokePropertyChanged = true
});
break;
case NotifyViewChangedAction.Reset:
case NotifyCollectionChangedAction.Reset:
eventDispatcher.Post(new CollectionEventDispatcherEventArgs(NotifyCollectionChangedAction.Reset)
{
Collection = this,
@ -190,7 +187,7 @@ namespace ObservableCollections.Internal
IsInvokePropertyChanged = true
});
break;
case NotifyViewChangedAction.Replace:
case NotifyCollectionChangedAction.Replace:
eventDispatcher.Post(new CollectionEventDispatcherEventArgs(NotifyCollectionChangedAction.Replace, args.NewView, args.OldView, args.NewViewIndex)
{
Collection = this,
@ -199,7 +196,7 @@ namespace ObservableCollections.Internal
IsInvokePropertyChanged = false
});
break;
case NotifyViewChangedAction.Move:
case NotifyCollectionChangedAction.Move:
eventDispatcher.Post(new CollectionEventDispatcherEventArgs(NotifyCollectionChangedAction.Move, args.NewView, args.NewViewIndex, args.OldViewIndex)
{
Collection = this,
@ -245,7 +242,7 @@ namespace ObservableCollections.Internal
static bool IsCompatibleObject(object? value)
{
return (value is T) || (value == null && default(T) == null);
return value is T || value == null && default(T) == null;
}
public bool IsReadOnly => true;

View File

@ -24,7 +24,6 @@ namespace ObservableCollections.Tests
void Equal(params int[] expected)
{
dict.Select(x => x.Value).OrderByDescending(x => x).Should().Equal(expected);
view.Select(x => x.Value.Value).OrderByDescending(x => x).Should().Equal(expected);
}
Equal(-10, -20, -30, -40, -50);
@ -42,146 +41,6 @@ namespace ObservableCollections.Tests
Equal(new int[0]);
}
[Fact]
public void ViewSorted()
{
var dict = new ObservableDictionary<int, int>();
var view1 = dict.CreateSortedView(x => x.Key, x => new ViewContainer<int>(x.Value), x => x.Value, true);
var view2 = dict.CreateSortedView(x => x.Key, x => new ViewContainer<int>(x.Value), x => x.Value, false);
dict.Add(10, 10); // 0
dict.Add(50, 50); // 1
dict.Add(30, 30); // 2
dict.Add(20, 20); // 3
dict.Add(40, 40); // 4
void Equal(params int[] expected)
{
dict.Select(x => x.Value).OrderBy(x => x).Should().Equal(expected);
view1.Select(x => x.Value.Value).Should().Equal(expected);
view2.Select(x => x.Value.Value).Should().Equal(expected.OrderByDescending(x => x));
}
Equal(10, 20, 30, 40, 50);
dict[99] = 100;
Equal(10, 20, 30, 40, 50, 100);
dict[10] = -5;
Equal(-5, 20, 30, 40, 50, 100);
dict.Remove(20);
Equal(-5, 30, 40, 50, 100);
dict.Clear();
Equal(new int[0]);
}
[Fact]
public void Freezed()
{
var dict = new FreezedDictionary<int, int>(new Dictionary<int, int>
{
[10] = 10,
[50] = 50,
[30] = 30,
[20] = 20,
[40] = 40,
[60] = 60
});
var view = dict.CreateSortableView(x => new ViewContainer<int>(x.Value));
view.Sort(x => x.Key, true);
view.Select(x => x.Value.Value).Should().Equal(10, 20, 30, 40, 50, 60);
view.Select(x => x.View).Should().Equal(10, 20, 30, 40, 50, 60);
view.Sort(x => x.Key, false);
view.Select(x => x.Value.Value).Should().Equal(60, 50, 40, 30, 20, 10);
view.Select(x => x.View).Should().Equal(60, 50, 40, 30, 20, 10);
}
[Fact]
public void FilterTest()
{
var dict = new ObservableDictionary<int, int>();
var view1 = dict.CreateView(x => new ViewContainer<int>(x.Value));
var view2 = dict.CreateSortedView(x => x.Key, x => new ViewContainer<int>(x.Value), x => x.Value, true);
var view3 = dict.CreateSortedView(x => new ViewContainer<int>(x.Value), x => x.Value, viewComparer: Comparer<ViewContainer<int>>.Default);
var filter1 = new TestFilter2<int>((x, v) => x.Value % 2 == 0);
var filter2 = new TestFilter2<int>((x, v) => x.Value % 2 == 0);
var filter3 = 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);
view2.AttachFilter(filter2);
view3.AttachFilter(filter3);
filter1.CalledWhenTrue.Select(x => x.Item1.Value).Should().Equal(-12, -34, -40);
filter2.CalledWhenTrue.Select(x => x.Item1.Value).Should().Equal(-40, -34, -12);
filter3.CalledWhenTrue.Select(x => x.Item1.Value).Should().Equal(-40, -34, -12);
dict.Add(99, -100);
filter1.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue.Value)).Should().Equal((NotifyCollectionChangedAction.Add, -100));
filter2.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue.Value)).Should().Equal((NotifyCollectionChangedAction.Add, -100));
filter3.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue.Value)).Should().Equal((NotifyCollectionChangedAction.Add, -100));
foreach (var item in new[] { filter1, filter2, filter3 }) item.CalledOnCollectionChanged.Clear();
dict[10] = -1090;
filter1.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue.Value, x.OldValue.Value)).Should().Equal((NotifyCollectionChangedAction.Replace, -1090, -12));
filter2.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue.Value, x.OldValue.Value)).Should().Equal((NotifyCollectionChangedAction.Replace, -1090, -12));
filter3.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue.Value, x.OldValue.Value)).Should().Equal((NotifyCollectionChangedAction.Replace, -1090, -12));
foreach (var item in new[] { filter1, filter2, filter3 }) item.CalledOnCollectionChanged.Clear();
dict.Remove(20);
filter1.CalledOnCollectionChanged.Select(x => (x.Action, x.OldValue.Value)).Should().Equal((NotifyCollectionChangedAction.Remove, -25));
filter2.CalledOnCollectionChanged.Select(x => (x.Action, x.OldValue.Value)).Should().Equal((NotifyCollectionChangedAction.Remove, -25));
filter3.CalledOnCollectionChanged.Select(x => (x.Action, x.OldValue.Value)).Should().Equal((NotifyCollectionChangedAction.Remove, -25));
foreach (var item in new[] { filter1, filter2, filter3 }) item.CalledOnCollectionChanged.Clear();
dict.Clear();
filter1.CalledOnCollectionChanged.Select(x => x.Action)
.Should().Equal(NotifyCollectionChangedAction.Reset);
filter2.CalledOnCollectionChanged.Select(x => x.Action)
.Should().Equal(NotifyCollectionChangedAction.Reset);
filter3.CalledOnCollectionChanged.Select(x => x.Action)
.Should().Equal(NotifyCollectionChangedAction.Reset);
}
[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].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter1.CalledOnCollectionChanged[0].NewValue.Key.Should().Be(10);
filter1.CalledOnCollectionChanged[1].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter1.CalledOnCollectionChanged[1].NewValue.Key.Should().Be(50);
filter1.CalledOnCollectionChanged[2].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter1.CalledOnCollectionChanged[2].NewValue.Key.Should().Be(30);
filter1.CalledOnCollectionChanged[3].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter1.CalledOnCollectionChanged[3].NewValue.Key.Should().Be(20);
filter1.CalledOnCollectionChanged[4].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter1.CalledOnCollectionChanged[4].NewValue.Key.Should().Be(40);
filter1.CalledWhenTrue.Count.Should().Be(3);
filter1.CalledWhenFalse.Count.Should().Be(2);
}
}
}

View File

@ -27,7 +27,6 @@ namespace ObservableCollections.Tests
{
set.Should().BeEquivalentTo(expected);
view.Select(x => x.Value).Should().BeEquivalentTo(expected);
view.Select(x => x.View.Value).Should().BeEquivalentTo(expected);
}
Equal(10, 50, 30, 20, 40);
@ -46,68 +45,7 @@ namespace ObservableCollections.Tests
Equal();
}
[Fact]
public void Filter()
{
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);
filter.CalledWhenTrue.Select(x => x.Item1).Should().Equal(30);
filter.CalledWhenFalse.Select(x => x.Item1).Should().Equal(10, 50, 20, 40);
view.Select(x => x.Value).Should().Equal(30);
filter.Clear();
set.Add(33);
set.AddRange(new[] { 98 });
filter.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue)).Should().Equal((NotifyCollectionChangedAction.Add, 33), (NotifyCollectionChangedAction.Add, 98));
filter.Clear();
set.Remove(10);
set.RemoveRange(new[] { 50, 30 });
filter.CalledOnCollectionChanged.Select(x => (x.Action, x.OldValue)).Should().Equal((NotifyCollectionChangedAction.Remove, 10), (NotifyCollectionChangedAction.Remove, 50), (NotifyCollectionChangedAction.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].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[0].NewValue.Should().Be(10);
filter.CalledOnCollectionChanged[1].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[1].NewValue.Should().Be(50);
filter.CalledOnCollectionChanged[2].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[2].NewValue.Should().Be(30);
filter.CalledOnCollectionChanged[3].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[3].NewValue.Should().Be(20);
filter.CalledOnCollectionChanged[4].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[4].NewValue.Should().Be(40);
filter.CalledWhenTrue.Count.Should().Be(1);
filter.CalledWhenFalse.Count.Should().Be(4);
}
[Fact]
public void IndexOutOfRange()
{

View File

@ -27,14 +27,14 @@ namespace ObservableCollections.Tests
reference.Should().Equal(expected);
list.Should().Equal(expected);
view.Select(x => x.Value).Should().Equal(expected);
view.Select(x => x.View).Should().Equal(expected.Select(x => new ViewContainer<int>(x)));
view.Filtered.Select(x => x.View).Should().Equal(expected.Select(x => new ViewContainer<int>(x)));
}
void Equal2(params int[] expected)
{
list.Should().Equal(expected);
view.Select(x => x.Value).Should().Equal(expected);
view.Select(x => x.View).Should().Equal(expected.Select(x => new ViewContainer<int>(x)));
view.Filtered.Select(x => x.View).Should().Equal(expected.Select(x => new ViewContainer<int>(x)));
}
Equal(10, 50, 30, 20, 40);
@ -69,178 +69,107 @@ namespace ObservableCollections.Tests
Equal2(100, 400, 200, 300);
}
[Fact]
public void ViewSorted()
{
var list = new ObservableList<int>();
var view1 = list.CreateSortedView(x => x, x => new ViewContainer<int>(x), comparer: Comparer<int>.Default);
var view2 = list.CreateSortedView(x => x, x => new ViewContainer<int>(x), viewComparer: Comparer<ViewContainer<int>>.Default);
var view3 = list.CreateSortedView(x => x, x => new ViewContainer<int>(x), x => x, ascending: true);
var view4 = list.CreateSortedView(x => x, x => new ViewContainer<int>(x), x => x, ascending: false);
//[Fact]
//public void FilterTest()
//{
// var list = new ObservableList<int>();
// var view1 = list.CreateView(x => new ViewContainer<int>(x));
// list.AddRange(new[] { 10, 21, 30, 44, 45, 66, 90 });
list.Add(10); // 0
list.Add(50); // 1
list.Add(30); // 2
list.Add(20); // 3
list.Add(40); // 4
// var filter1 = new TestFilter<int>((x, v) => x % 2 == 0);
// var filter2 = new TestFilter<int>((x, v) => x % 2 == 0);
// var filter3 = new TestFilter<int>((x, v) => x % 2 == 0);
// view1.AttachFilter(filter1);
// view2.AttachFilter(filter2);
// view3.AttachFilter(filter3);
void Equal(params int[] expected)
{
list.Should().Equal(expected);
// filter1.CalledWhenTrue.Select(x => x.Item1).Should().Equal(10, 30, 44, 66, 90);
// filter2.CalledWhenTrue.Select(x => x.Item1).Should().Equal(10, 30, 44, 66, 90);
// filter3.CalledWhenTrue.Select(x => x.Item1).Should().Equal(10, 30, 44, 66, 90);
var sorted = expected.OrderBy(x => x).ToArray();
view1.Select(x => x.Value).Should().Equal(sorted);
view2.Select(x => x.View).Should().Equal(sorted.Select(x => new ViewContainer<int>(x)));
view3.Select(x => x.Value).Should().Equal(sorted);
view4.Select(x => x.Value).Should().Equal(expected.OrderByDescending(x => x).ToArray());
}
// filter1.CalledWhenFalse.Select(x => x.Item1).Should().Equal(21, 45);
// filter2.CalledWhenFalse.Select(x => x.Item1).Should().Equal(21, 45);
// filter3.CalledWhenFalse.Select(x => x.Item1).Should().Equal(21, 45);
Equal(10, 50, 30, 20, 40);
// view1.Select(x => x.Value).Should().Equal(10, 30, 44, 66, 90);
// view2.Select(x => x.Value).Should().Equal(10, 30, 44, 66, 90);
// view3.Select(x => x.Value).Should().Equal(10, 30, 44, 66, 90);
list.Move(3, 1);
Equal(10, 20, 50, 30, 40);
// filter1.Clear();
// filter2.Clear();
// filter3.Clear();
list.Insert(2, 99);
Equal(10, 20, 99, 50, 30, 40);
// list.Add(100);
// list.AddRange(new[] { 101 });
// filter1.CalledWhenTrue.Select(x => x.Item1).Should().Equal(100);
// filter2.CalledWhenTrue.Select(x => x.Item1).Should().Equal(100);
// filter3.CalledWhenTrue.Select(x => x.Item1).Should().Equal(100);
// filter1.CalledWhenFalse.Select(x => x.Item1).Should().Equal(101);
// filter2.CalledWhenFalse.Select(x => x.Item1).Should().Equal(101);
// filter3.CalledWhenFalse.Select(x => x.Item1).Should().Equal(101);
list.RemoveAt(2);
Equal(10, 20, 50, 30, 40);
// filter1.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 100, 7), (NotifyCollectionChangedAction.Add, 101, 8));
// filter2.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 100, 7), (NotifyCollectionChangedAction.Add, 101, 8));
// filter3.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 100, 7), (NotifyCollectionChangedAction.Add, 101, 8));
list[3] = 88;
Equal(10, 20, 50, 88, 40);
// foreach (var item in new[] { filter1, filter2, filter3 }) item.CalledOnCollectionChanged.Clear();
list.Clear();
Equal(new int[0]);
// list.Insert(0, 1000);
// list.InsertRange(0, new[] { 999 });
list.AddRange(new[] { 100, 200, 300 });
Equal(100, 200, 300);
// filter1.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 1000, 0), (NotifyCollectionChangedAction.Add, 999, 0));
// filter2.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 1000, 9), (NotifyCollectionChangedAction.Add, 999, 9)); // sorted index
// filter3.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 1000, 9), (NotifyCollectionChangedAction.Add, 999, 9)); // sorted index
// foreach (var item in new[] { filter1, filter2, filter3 }) item.CalledOnCollectionChanged.Clear();
list.InsertRange(1, new[] { 400, 500, 600 });
Equal(100, 400, 500, 600, 200, 300);
// list.RemoveAt(0);
// list.RemoveRange(0, 1);
list.RemoveRange(2, 2);
Equal(100, 400, 200, 300);
}
// filter1.CalledOnCollectionChanged.Select(x => (x.Action, x.OldValue, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Remove, 999, 0), (NotifyCollectionChangedAction.Remove, 1000, 0));
// filter2.CalledOnCollectionChanged.Select(x => (x.Action, x.OldValue, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Remove, 999, 9), (NotifyCollectionChangedAction.Remove, 1000, 9));
// filter3.CalledOnCollectionChanged.Select(x => (x.Action, x.OldValue, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Remove, 999, 9), (NotifyCollectionChangedAction.Remove, 1000, 9));
// foreach (var item in new[] { filter1, filter2, filter3 }) item.CalledOnCollectionChanged.Clear();
[Fact]
public void Freezed()
{
var list = new FreezedList<int>(new[] { 10, 20, 50, 30, 40, 60 });
// list[0] = 9999;
var view = list.CreateSortableView(x => new ViewContainer<int>(x));
// filter1.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Replace, 9999, 0, 0));
// filter2.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Replace, 9999, 8, 0));
// filter3.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Replace, 9999, 8, 0));
// foreach (var item in new[] { filter1, filter2, filter3 }) item.CalledOnCollectionChanged.Clear();
view.Sort(x => x, true);
view.Select(x => x.Value).Should().Equal(10, 20, 30, 40, 50, 60);
view.Select(x => x.View).Should().Equal(10, 20, 30, 40, 50, 60);
// list.Move(3, 0);
// filter1.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Move, 44, 0, 3));
// filter2.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Move, 44, 2, 2));
// filter3.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Move, 44, 2, 2));
// foreach (var item in new[] { filter1, filter2, filter3 }) item.CalledOnCollectionChanged.Clear();
view.Sort(x => x, false);
view.Select(x => x.Value).Should().Equal(60, 50, 40, 30, 20, 10);
view.Select(x => x.View).Should().Equal(60, 50, 40, 30, 20, 10);
}
// list.Clear();
// filter1.CalledOnCollectionChanged.Select(x => x.Action).Should().Equal(NotifyCollectionChangedAction.Reset);
// filter2.CalledOnCollectionChanged.Select(x => x.Action).Should().Equal(NotifyCollectionChangedAction.Reset);
// filter3.CalledOnCollectionChanged.Select(x => x.Action).Should().Equal(NotifyCollectionChangedAction.Reset);
//}
[Fact]
public void FilterTest()
{
var list = new ObservableList<int>();
var view1 = list.CreateView(x => new ViewContainer<int>(x));
var view2 = list.CreateSortedView(x => x, x => new ViewContainer<int>(x), comparer: Comparer<int>.Default);
var view3 = list.CreateSortedView(x => x, x => new ViewContainer<int>(x), viewComparer: Comparer<ViewContainer<int>>.Default);
list.AddRange(new[] { 10, 21, 30, 44, 45, 66, 90 });
//[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);
var filter2 = new TestFilter<int>((x, v) => x % 2 == 0);
var filter3 = new TestFilter<int>((x, v) => x % 2 == 0);
view1.AttachFilter(filter1);
view2.AttachFilter(filter2);
view3.AttachFilter(filter3);
filter1.CalledWhenTrue.Select(x => x.Item1).Should().Equal(10, 30, 44, 66, 90);
filter2.CalledWhenTrue.Select(x => x.Item1).Should().Equal(10, 30, 44, 66, 90);
filter3.CalledWhenTrue.Select(x => x.Item1).Should().Equal(10, 30, 44, 66, 90);
filter1.CalledWhenFalse.Select(x => x.Item1).Should().Equal(21, 45);
filter2.CalledWhenFalse.Select(x => x.Item1).Should().Equal(21, 45);
filter3.CalledWhenFalse.Select(x => x.Item1).Should().Equal(21, 45);
view1.Select(x => x.Value).Should().Equal(10, 30, 44, 66, 90);
view2.Select(x => x.Value).Should().Equal(10, 30, 44, 66, 90);
view3.Select(x => x.Value).Should().Equal(10, 30, 44, 66, 90);
filter1.Clear();
filter2.Clear();
filter3.Clear();
list.Add(100);
list.AddRange(new[] { 101 });
filter1.CalledWhenTrue.Select(x => x.Item1).Should().Equal(100);
filter2.CalledWhenTrue.Select(x => x.Item1).Should().Equal(100);
filter3.CalledWhenTrue.Select(x => x.Item1).Should().Equal(100);
filter1.CalledWhenFalse.Select(x => x.Item1).Should().Equal(101);
filter2.CalledWhenFalse.Select(x => x.Item1).Should().Equal(101);
filter3.CalledWhenFalse.Select(x => x.Item1).Should().Equal(101);
filter1.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 100, 7), (NotifyCollectionChangedAction.Add, 101, 8));
filter2.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 100, 7), (NotifyCollectionChangedAction.Add, 101, 8));
filter3.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 100, 7), (NotifyCollectionChangedAction.Add, 101, 8));
foreach (var item in new[] { filter1, filter2, filter3 }) item.CalledOnCollectionChanged.Clear();
list.Insert(0, 1000);
list.InsertRange(0, new[] { 999 });
filter1.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 1000, 0), (NotifyCollectionChangedAction.Add, 999, 0));
filter2.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 1000, 9), (NotifyCollectionChangedAction.Add, 999, 9)); // sorted index
filter3.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 1000, 9), (NotifyCollectionChangedAction.Add, 999, 9)); // sorted index
foreach (var item in new[] { filter1, filter2, filter3 }) item.CalledOnCollectionChanged.Clear();
list.RemoveAt(0);
list.RemoveRange(0, 1);
filter1.CalledOnCollectionChanged.Select(x => (x.Action, x.OldValue, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Remove, 999, 0), (NotifyCollectionChangedAction.Remove, 1000, 0));
filter2.CalledOnCollectionChanged.Select(x => (x.Action, x.OldValue, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Remove, 999, 9), (NotifyCollectionChangedAction.Remove, 1000, 9));
filter3.CalledOnCollectionChanged.Select(x => (x.Action, x.OldValue, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Remove, 999, 9), (NotifyCollectionChangedAction.Remove, 1000, 9));
foreach (var item in new[] { filter1, filter2, filter3 }) item.CalledOnCollectionChanged.Clear();
list[0] = 9999;
filter1.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Replace, 9999, 0, 0));
filter2.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Replace, 9999, 8, 0));
filter3.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Replace, 9999, 8, 0));
foreach (var item in new[] { filter1, filter2, filter3 }) item.CalledOnCollectionChanged.Clear();
list.Move(3, 0);
filter1.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Move, 44, 0, 3));
filter2.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Move, 44, 2, 2));
filter3.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Move, 44, 2, 2));
foreach (var item in new[] { filter1, filter2, filter3 }) item.CalledOnCollectionChanged.Clear();
list.Clear();
filter1.CalledOnCollectionChanged.Select(x => x.Action).Should().Equal(NotifyCollectionChangedAction.Reset);
filter2.CalledOnCollectionChanged.Select(x => x.Action).Should().Equal(NotifyCollectionChangedAction.Reset);
filter3.CalledOnCollectionChanged.Select(x => x.Action).Should().Equal(NotifyCollectionChangedAction.Reset);
}
[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);
// var filter1 = new TestFilter<int>((x, v) => x % 2 == 0);
// view1.AttachFilter(filter1);
filter1.CalledOnCollectionChanged[0].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter1.CalledOnCollectionChanged[0].NewValue.Should().Be(10);
filter1.CalledOnCollectionChanged[1].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter1.CalledOnCollectionChanged[1].NewValue.Should().Be(21);
filter1.CalledOnCollectionChanged[2].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter1.CalledOnCollectionChanged[2].NewValue.Should().Be(30);
filter1.CalledOnCollectionChanged[3].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter1.CalledOnCollectionChanged[3].NewValue.Should().Be(44);
// filter1.CalledOnCollectionChanged[0].Action.Should().Be(NotifyCollectionChangedAction.Add);
// filter1.CalledOnCollectionChanged[0].NewValue.Should().Be(10);
// filter1.CalledOnCollectionChanged[1].Action.Should().Be(NotifyCollectionChangedAction.Add);
// filter1.CalledOnCollectionChanged[1].NewValue.Should().Be(21);
// filter1.CalledOnCollectionChanged[2].Action.Should().Be(NotifyCollectionChangedAction.Add);
// filter1.CalledOnCollectionChanged[2].NewValue.Should().Be(30);
// filter1.CalledOnCollectionChanged[3].Action.Should().Be(NotifyCollectionChangedAction.Add);
// filter1.CalledOnCollectionChanged[3].NewValue.Should().Be(44);
filter1.CalledWhenTrue.Count.Should().Be(3);
filter1.CalledWhenFalse.Count.Should().Be(1);
}
// filter1.CalledWhenTrue.Count.Should().Be(3);
// filter1.CalledWhenFalse.Count.Should().Be(1);
//}
}
}

View File

@ -27,7 +27,6 @@ namespace ObservableCollections.Tests
{
queue.Should().Equal(expected);
view.Select(x => x.Value).Should().Equal(expected);
view.Select(x => x.View).Should().Equal(expected.Select(x => new ViewContainer<int>(x)));
}
Equal(10, 50, 30, 20, 40);
@ -50,72 +49,72 @@ namespace ObservableCollections.Tests
Equal();
}
[Fact]
public void Filter()
{
var queue = new ObservableQueue<int>();
var view = queue.CreateView(x => new ViewContainer<int>(x));
var filter = new TestFilter<int>((x, v) => x % 3 == 0);
//[Fact]
//public void Filter()
//{
// 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);
// queue.Enqueue(10);
// queue.Enqueue(50);
// queue.Enqueue(30);
// queue.Enqueue(20);
// queue.Enqueue(40);
view.AttachFilter(filter);
filter.CalledWhenTrue.Select(x => x.Item1).Should().Equal(30);
filter.CalledWhenFalse.Select(x => x.Item1).Should().Equal(10, 50, 20, 40);
// view.AttachFilter(filter);
// filter.CalledWhenTrue.Select(x => x.Item1).Should().Equal(30);
// filter.CalledWhenFalse.Select(x => x.Item1).Should().Equal(10, 50, 20, 40);
view.Select(x => x.Value).Should().Equal(30);
// view.Select(x => x.Value).Should().Equal(30);
filter.Clear();
// filter.Clear();
queue.Enqueue(33);
queue.EnqueueRange(new[] { 98 });
// queue.Enqueue(33);
// queue.EnqueueRange(new[] { 98 });
filter.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 33, 5), (NotifyCollectionChangedAction.Add, 98, 6));
filter.Clear();
// filter.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 33, 5), (NotifyCollectionChangedAction.Add, 98, 6));
// filter.Clear();
queue.Dequeue();
queue.DequeueRange(2);
filter.CalledOnCollectionChanged.Select(x => (x.Action, x.OldValue, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Remove, 10, 0), (NotifyCollectionChangedAction.Remove, 50, 0), (NotifyCollectionChangedAction.Remove, 30, 0));
}
// queue.Dequeue();
// queue.DequeueRange(2);
// filter.CalledOnCollectionChanged.Select(x => (x.Action, x.OldValue, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Remove, 10, 0), (NotifyCollectionChangedAction.Remove, 50, 0), (NotifyCollectionChangedAction.Remove, 30, 0));
//}
[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);
//[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);
// queue.Enqueue(10);
// queue.Enqueue(50);
// queue.Enqueue(30);
// queue.Enqueue(20);
// queue.Enqueue(40);
view.AttachFilter(filter, true);
// view.AttachFilter(filter, true);
filter.CalledOnCollectionChanged.Count.Should().Be(5);
filter.CalledOnCollectionChanged[0].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[0].NewValue.Should().Be(10);
filter.CalledOnCollectionChanged[0].NewViewIndex.Should().Be(0);
filter.CalledOnCollectionChanged[1].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[1].NewValue.Should().Be(50);
filter.CalledOnCollectionChanged[1].NewViewIndex.Should().Be(1);
filter.CalledOnCollectionChanged[2].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[2].NewValue.Should().Be(30);
filter.CalledOnCollectionChanged[2].NewViewIndex.Should().Be(2);
filter.CalledOnCollectionChanged[3].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[3].NewValue.Should().Be(20);
filter.CalledOnCollectionChanged[3].NewViewIndex.Should().Be(3);
filter.CalledOnCollectionChanged[4].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[4].NewValue.Should().Be(40);
filter.CalledOnCollectionChanged[4].NewViewIndex.Should().Be(4);
// filter.CalledOnCollectionChanged.Count.Should().Be(5);
// filter.CalledOnCollectionChanged[0].Action.Should().Be(NotifyCollectionChangedAction.Add);
// filter.CalledOnCollectionChanged[0].NewValue.Should().Be(10);
// filter.CalledOnCollectionChanged[0].NewViewIndex.Should().Be(0);
// filter.CalledOnCollectionChanged[1].Action.Should().Be(NotifyCollectionChangedAction.Add);
// filter.CalledOnCollectionChanged[1].NewValue.Should().Be(50);
// filter.CalledOnCollectionChanged[1].NewViewIndex.Should().Be(1);
// filter.CalledOnCollectionChanged[2].Action.Should().Be(NotifyCollectionChangedAction.Add);
// filter.CalledOnCollectionChanged[2].NewValue.Should().Be(30);
// filter.CalledOnCollectionChanged[2].NewViewIndex.Should().Be(2);
// filter.CalledOnCollectionChanged[3].Action.Should().Be(NotifyCollectionChangedAction.Add);
// filter.CalledOnCollectionChanged[3].NewValue.Should().Be(20);
// filter.CalledOnCollectionChanged[3].NewViewIndex.Should().Be(3);
// filter.CalledOnCollectionChanged[4].Action.Should().Be(NotifyCollectionChangedAction.Add);
// filter.CalledOnCollectionChanged[4].NewValue.Should().Be(40);
// filter.CalledOnCollectionChanged[4].NewViewIndex.Should().Be(4);
filter.CalledWhenTrue.Count.Should().Be(1);
filter.CalledWhenFalse.Count.Should().Be(4);
}
// filter.CalledWhenTrue.Count.Should().Be(1);
// filter.CalledWhenFalse.Count.Should().Be(4);
//}
}
}

View File

@ -24,7 +24,6 @@ namespace ObservableCollections.Tests
{
buf.Should().Equal(expected);
view.Select(x => x.Value).Should().Equal(expected);
view.Select(x => x.View).Should().Equal(expected.Select(x => new ViewContainer<int>(x)));
}
Equal(10, 50, 30, 20, 40);
@ -65,7 +64,6 @@ namespace ObservableCollections.Tests
{
buf.Should().Equal(expected);
view.Select(x => x.Value).Should().Equal(expected);
view.Select(x => x.View).Should().Equal(expected.Select(x => new ViewContainer<int>(x)));
}
buf.AddLast(10);

View File

@ -27,7 +27,6 @@ namespace ObservableCollections.Tests
{
stack.Should().Equal(expected);
view.Select(x => x.Value).Should().Equal(expected);
view.Select(x => x.View).Should().Equal(expected.Select(x => new ViewContainer<int>(x)));
}
Equal(40, 20, 30, 50, 10);
@ -50,72 +49,6 @@ namespace ObservableCollections.Tests
Equal();
}
[Fact]
public void Filter()
{
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);
filter.CalledWhenTrue.Select(x => x.Item1).Should().Equal(30);
filter.CalledWhenFalse.Select(x => x.Item1).Should().Equal(40, 20, 50, 10);
view.Select(x => x.Value).Should().Equal(30);
filter.Clear();
stack.Push(33);
stack.PushRange(new[] { 98 });
filter.CalledOnCollectionChanged.Select(x => (x.Action, x.NewValue, x.NewViewIndex)).Should().Equal((NotifyCollectionChangedAction.Add, 33, 0), (NotifyCollectionChangedAction.Add, 98, 0));
filter.Clear();
stack.Pop();
stack.PopRange(2);
filter.CalledOnCollectionChanged.Select(x => (x.Action, x.OldValue, x.OldViewIndex)).Should().Equal((NotifyCollectionChangedAction.Remove, 98, 0), (NotifyCollectionChangedAction.Remove, 33, 0), (NotifyCollectionChangedAction.Remove, 40, 0));
}
[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].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[4].NewValue.Should().Be(10);
filter.CalledOnCollectionChanged[4].NewViewIndex.Should().Be(0);
filter.CalledOnCollectionChanged[3].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[3].NewValue.Should().Be(50);
filter.CalledOnCollectionChanged[3].NewViewIndex.Should().Be(0);
filter.CalledOnCollectionChanged[2].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[2].NewValue.Should().Be(30);
filter.CalledOnCollectionChanged[2].NewViewIndex.Should().Be(0);
filter.CalledOnCollectionChanged[1].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[1].NewValue.Should().Be(20);
filter.CalledOnCollectionChanged[1].NewViewIndex.Should().Be(0);
filter.CalledOnCollectionChanged[0].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[0].NewValue.Should().Be(40);
filter.CalledOnCollectionChanged[0].NewViewIndex.Should().Be(0);
filter.CalledWhenTrue.Count.Should().Be(1);
filter.CalledWhenFalse.Count.Should().Be(4);
}
}
}

View File

@ -1,70 +0,0 @@
using System.Collections.Generic;
using System.Collections.Specialized;
namespace ObservableCollections.Tests;
public class SortedViewTest
{
[Fact]
public void Sort()
{
var list = new ObservableList<int>();
var sortedView = list.CreateSortedView(
x => x,
x => new ViewContainer<int>(x),
Comparer<int>.Default);
list.Add(10);
list.Add(50);
list.Add(30);
list.Add(20);
list.Add(40);
using var e = sortedView.GetEnumerator();
e.MoveNext().Should().BeTrue();
e.Current.Value.Should().Be(10);
e.MoveNext().Should().BeTrue();
e.Current.Value.Should().Be(20);
e.MoveNext().Should().BeTrue();
e.Current.Value.Should().Be(30);
e.MoveNext().Should().BeTrue();
e.Current.Value.Should().Be(40);
e.MoveNext().Should().BeTrue();
e.Current.Value.Should().Be(50);
e.MoveNext().Should().BeFalse();
}
[Fact]
public void ObserveIndex()
{
var list = new ObservableList<int>();
var sortedView = list.CreateSortedView(
x => x,
x => new ViewContainer<int>(x),
Comparer<int>.Default);
var filter = new TestFilter<int>((value, view) => value % 2 == 0);
list.Add(50);
list.Add(10);
sortedView.AttachFilter(filter);
list.Add(20);
filter.CalledOnCollectionChanged[0].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[0].NewValue.Should().Be(20);
filter.CalledOnCollectionChanged[0].NewView.Should().Be(new ViewContainer<int>(20));
filter.CalledOnCollectionChanged[0].NewViewIndex.Should().Be(1);
list.Remove(20);
filter.CalledOnCollectionChanged[1].Action.Should().Be(NotifyCollectionChangedAction.Remove);
filter.CalledOnCollectionChanged[1].OldValue.Should().Be(20);
filter.CalledOnCollectionChanged[1].OldView.Should().Be(new ViewContainer<int>(20));
filter.CalledOnCollectionChanged[1].OldViewIndex.Should().Be(1);
list[1] = 999; // from 10(at 0 in original) to 999
filter.CalledOnCollectionChanged[2].Action.Should().Be(NotifyCollectionChangedAction.Replace);
filter.CalledOnCollectionChanged[2].NewValue.Should().Be(999);
filter.CalledOnCollectionChanged[2].OldValue.Should().Be(10);
filter.CalledOnCollectionChanged[2].NewViewIndex.Should().Be(1);
}
}

View File

@ -1,73 +0,0 @@
using System.Collections.Generic;
using System.Collections.Specialized;
namespace ObservableCollections.Tests;
public class SortedViewViewComparerTest
{
[Fact]
public void Sort()
{
var list = new ObservableList<int>();
var sortedView = list.CreateSortedView(
x => x,
x => new ViewContainer<int>(x),
Comparer<ViewContainer<int>>.Default);
list.Add(10);
list.Add(50);
list.Add(30);
list.Add(20);
list.Add(40);
using var e = sortedView.GetEnumerator();
e.MoveNext().Should().BeTrue();
e.Current.Value.Should().Be(10);
e.MoveNext().Should().BeTrue();
e.Current.Value.Should().Be(20);
e.MoveNext().Should().BeTrue();
e.Current.Value.Should().Be(30);
e.MoveNext().Should().BeTrue();
e.Current.Value.Should().Be(40);
e.MoveNext().Should().BeTrue();
e.Current.Value.Should().Be(50);
e.MoveNext().Should().BeFalse();
}
[Fact]
public void ObserveIndex()
{
var list = new ObservableList<int>();
var sortedView = list.CreateSortedView(
x => x,
x => new ViewContainer<int>(x),
Comparer<ViewContainer<int>>.Default);
var filter = new TestFilter<int>((value, view) => value % 2 == 0);
list.Add(50);
list.Add(10);
sortedView.AttachFilter(filter);
list.Add(20);
filter.CalledOnCollectionChanged[0].Action.Should().Be(NotifyCollectionChangedAction.Add);
filter.CalledOnCollectionChanged[0].NewValue.Should().Be(20);
filter.CalledOnCollectionChanged[0].NewView.Should().Be(new ViewContainer<int>(20));
filter.CalledOnCollectionChanged[0].NewViewIndex.Should().Be(1);
list.Remove(20);
filter.CalledOnCollectionChanged[1].Action.Should().Be(NotifyCollectionChangedAction.Remove);
filter.CalledOnCollectionChanged[1].OldValue.Should().Be(20);
filter.CalledOnCollectionChanged[1].OldView.Should().Be(new ViewContainer<int>(20));
filter.CalledOnCollectionChanged[1].OldViewIndex.Should().Be(1);
list[1] = 999; // from 10(at 0 in original) to 999
filter.CalledOnCollectionChanged[2].Action.Should().Be(NotifyCollectionChangedAction.Replace);
filter.CalledOnCollectionChanged[2].NewValue.Should().Be(999);
filter.CalledOnCollectionChanged[2].OldValue.Should().Be(10);
filter.CalledOnCollectionChanged[2].NewView.Should().Be(new ViewContainer<int>(999));
filter.CalledOnCollectionChanged[2].OldView.Should().Be(new ViewContainer<int>(10));
filter.CalledOnCollectionChanged[2].NewViewIndex.Should().Be(1);
filter.CalledOnCollectionChanged[2].OldViewIndex.Should().Be(0);
}
}

View File

@ -1,3 +1,5 @@
using ObservableCollections;
namespace ObservableCollections.Tests;
public class ToNotifyCollectionChangedTest
@ -43,7 +45,7 @@ public class ToNotifyCollectionChangedTest
var view = list.CreateView(x => $"${x}");
var notify = view.ToNotifyCollectionChanged();
view.AttachFilter((value, view) => value % 2 == 0);
view.AttachFilter((value) => value % 2 == 0);
list.Add(4);

View File

@ -31,83 +31,81 @@ namespace ObservableCollections.Tests
}
}
public class TestFilter<T> : ISynchronizedViewFilter<T, ViewContainer<T>>
{
readonly Func<T, ViewContainer<T>, bool> filter;
public List<(T, ViewContainer<T>)> CalledWhenTrue = new();
public List<(T, ViewContainer<T>)> CalledWhenFalse = new();
public List<SynchronizedViewChangedEventArgs<T, ViewContainer<T>>> CalledOnCollectionChanged = new();
//public class TestFilter<T> : ISynchronizedViewFilter<T>
//{
// readonly Func<T, bool> filter;
// public List<SynchronizedViewChangedEventArgs<T, ViewContainer<T>>> CalledOnCollectionChanged = new();
public TestFilter(Func<T, ViewContainer<T>, bool> filter)
{
this.filter = filter;
}
// public TestFilter(Func<T, bool> filter)
// {
// this.filter = filter;
// }
public void Clear()
{
CalledWhenTrue.Clear();
CalledWhenFalse.Clear();
CalledOnCollectionChanged.Clear();
}
// public void Clear()
// {
// CalledWhenTrue.Clear();
// CalledWhenFalse.Clear();
// CalledOnCollectionChanged.Clear();
// }
public bool IsMatch(T value, ViewContainer<T> view)
{
return this.filter.Invoke(value, view);
}
// public bool IsMatch(T value)
// {
// return this.filter.Invoke(value);
// }
public void OnCollectionChanged(in SynchronizedViewChangedEventArgs<T, ViewContainer<T>> args)
{
CalledOnCollectionChanged.Add(args);
}
// public void OnCollectionChanged(in SynchronizedViewChangedEventArgs<T, ViewContainer<T>> args)
// {
// CalledOnCollectionChanged.Add(args);
// }
public void WhenTrue(T value, ViewContainer<T> view)
{
CalledWhenTrue.Add((value, view));
}
// public void WhenTrue(T value, ViewContainer<T> view)
// {
// CalledWhenTrue.Add((value, view));
// }
public void WhenFalse(T value, ViewContainer<T> view)
{
CalledWhenFalse.Add((value, view));
}
}
// public void WhenFalse(T value, ViewContainer<T> view)
// {
// CalledWhenFalse.Add((value, view));
// }
//}
public class TestFilter2<T> : ISynchronizedViewFilter<KeyValuePair<T, T>, ViewContainer<T>>
{
readonly Func<KeyValuePair<T, T>, ViewContainer<T>, bool> filter;
public List<(KeyValuePair<T, T>, ViewContainer<T>)> CalledWhenTrue = new();
public List<(KeyValuePair<T, T>, ViewContainer<T>)> CalledWhenFalse = new();
public List<SynchronizedViewChangedEventArgs<KeyValuePair<T, T>, ViewContainer<T>>> CalledOnCollectionChanged = new();
//public class TestFilter2<T> : ISynchronizedViewFilter<KeyValuePair<T, T>, ViewContainer<T>>
//{
// readonly Func<KeyValuePair<T, T>, ViewContainer<T>, bool> filter;
// public List<(KeyValuePair<T, T>, ViewContainer<T>)> CalledWhenTrue = new();
// public List<(KeyValuePair<T, T>, ViewContainer<T>)> CalledWhenFalse = new();
// public List<SynchronizedViewChangedEventArgs<KeyValuePair<T, T>, ViewContainer<T>>> CalledOnCollectionChanged = new();
public TestFilter2(Func<KeyValuePair<T, T>, ViewContainer<T>, bool> filter)
{
this.filter = filter;
}
// public TestFilter2(Func<KeyValuePair<T, T>, ViewContainer<T>, bool> filter)
// {
// this.filter = filter;
// }
public void Clear()
{
CalledWhenTrue.Clear();
CalledWhenFalse.Clear();
CalledOnCollectionChanged.Clear();
}
// public void Clear()
// {
// CalledWhenTrue.Clear();
// CalledWhenFalse.Clear();
// CalledOnCollectionChanged.Clear();
// }
public bool IsMatch(KeyValuePair<T, T> value, ViewContainer<T> view)
{
return this.filter.Invoke(value, view);
}
// public bool IsMatch(KeyValuePair<T, T> value, ViewContainer<T> view)
// {
// return this.filter.Invoke(value, view);
// }
public void OnCollectionChanged(in SynchronizedViewChangedEventArgs<KeyValuePair<T, T>, ViewContainer<T>> args)
{
CalledOnCollectionChanged.Add(args);
}
// public void OnCollectionChanged(in SynchronizedViewChangedEventArgs<KeyValuePair<T, T>, ViewContainer<T>> args)
// {
// CalledOnCollectionChanged.Add(args);
// }
public void WhenTrue(KeyValuePair<T, T> value, ViewContainer<T> view)
{
CalledWhenTrue.Add((value, view));
}
// public void WhenTrue(KeyValuePair<T, T> value, ViewContainer<T> view)
// {
// CalledWhenTrue.Add((value, view));
// }
public void WhenFalse(KeyValuePair<T, T> value, ViewContainer<T> view)
{
CalledWhenFalse.Add((value, view));
}
}
// public void WhenFalse(KeyValuePair<T, T> value, ViewContainer<T> view)
// {
// CalledWhenFalse.Add((value, view));
// }
//}
}