breaking changes, ISynchronizedView<T> -> ISynchronizedView<T, TView>

This commit is contained in:
neuecc 2024-10-18 21:07:20 +09:00
parent bd7cc350f2
commit 73c5b8e83e
10 changed files with 92 additions and 68 deletions

View File

@ -35,7 +35,7 @@ namespace ObservableCollections
public interface ISynchronizedView<T, TView> : IReadOnlyCollection<TView>, IDisposable public interface ISynchronizedView<T, TView> : IReadOnlyCollection<TView>, IDisposable
{ {
object SyncRoot { get; } object SyncRoot { get; }
ISynchronizedViewFilter<T> Filter { get; } ISynchronizedViewFilter<T, TView> Filter { get; }
IEnumerable<(T Value, TView View)> Filtered { get; } IEnumerable<(T Value, TView View)> Filtered { get; }
IEnumerable<(T Value, TView View)> Unfiltered { get; } IEnumerable<(T Value, TView View)> Unfiltered { get; }
int UnfilteredCount { get; } int UnfilteredCount { get; }
@ -44,7 +44,7 @@ namespace ObservableCollections
event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged; event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
event Action<NotifyCollectionChangedAction>? CollectionStateChanged; event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
void AttachFilter(ISynchronizedViewFilter<T> filter); void AttachFilter(ISynchronizedViewFilter<T, TView> filter);
void ResetFilter(); void ResetFilter();
ISynchronizedViewList<TView> ToViewList(); ISynchronizedViewList<TView> ToViewList();
NotifyCollectionChangedSynchronizedViewList<TView> ToNotifyCollectionChanged(); NotifyCollectionChangedSynchronizedViewList<TView> ToNotifyCollectionChanged();

View File

@ -1,24 +1,38 @@
using System; using System;
using System.Collections.Specialized;
namespace ObservableCollections namespace ObservableCollections
{ {
// Obsolete...
[Obsolete("this interface is obsoleted. Use ISynchronizedViewFilter<T, TView> instead.")]
public interface ISynchronizedViewFilter<T> public interface ISynchronizedViewFilter<T>
{ {
bool IsMatch(T value); bool IsMatch(T value);
} }
public class SynchronizedViewFilter<T>(Func<T, bool> isMatch) : ISynchronizedViewFilter<T> public interface ISynchronizedViewFilter<T, TView>
{ {
public static readonly ISynchronizedViewFilter<T> Null = new NullViewFilter(); bool IsMatch(T value, TView view);
}
public bool IsMatch(T value) => isMatch(value); internal class SynchronizedViewValueOnlyFilter<T, TView>(Func<T, bool> isMatch) : ISynchronizedViewFilter<T, TView>
{
public bool IsMatch(T value, TView view) => isMatch(value);
class NullViewFilter : ISynchronizedViewFilter<T> class NullViewFilter : ISynchronizedViewFilter<T, TView>
{ {
public bool IsMatch(T value) => true; public bool IsMatch(T value, TView view) => true;
} }
} }
public class SynchronizedViewFilter<T, TView>(Func<T, TView, bool> isMatch) : ISynchronizedViewFilter<T, TView>
{
public static readonly ISynchronizedViewFilter<T, TView> Null = new NullViewFilter();
public bool IsMatch(T value, TView view) => isMatch(value, view);
class NullViewFilter : ISynchronizedViewFilter<T, TView>
{
public bool IsMatch(T value, TView view) => true;
}
}
} }

View File

@ -19,7 +19,7 @@ namespace ObservableCollections
{ {
readonly ObservableDictionary<TKey, TValue> source; readonly ObservableDictionary<TKey, TValue> source;
readonly Func<KeyValuePair<TKey, TValue>, TView> selector; readonly Func<KeyValuePair<TKey, TValue>, TView> selector;
ISynchronizedViewFilter<KeyValuePair<TKey, TValue>> filter; ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> filter;
readonly Dictionary<TKey, (TValue, TView)> dict; readonly Dictionary<TKey, (TValue, TView)> dict;
int filteredCount; int filteredCount;
@ -27,7 +27,7 @@ namespace ObservableCollections
{ {
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>>.Null; this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
@ -42,7 +42,7 @@ namespace ObservableCollections
public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged; public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged; public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public ISynchronizedViewFilter<KeyValuePair<TKey, TValue>> Filter public ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> Filter
{ {
get { lock (SyncRoot) return filter; } get { lock (SyncRoot) return filter; }
} }
@ -74,7 +74,7 @@ namespace ObservableCollections
this.source.CollectionChanged -= SourceCollectionChanged; this.source.CollectionChanged -= SourceCollectionChanged;
} }
public void AttachFilter(ISynchronizedViewFilter<KeyValuePair<TKey, TValue>> filter) public void AttachFilter(ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> filter)
{ {
if (filter.IsNullFilter()) if (filter.IsNullFilter())
{ {
@ -89,7 +89,7 @@ namespace ObservableCollections
foreach (var v in dict) foreach (var v in dict)
{ {
var value = new KeyValuePair<TKey, TValue>(v.Key, v.Value.Item1); var value = new KeyValuePair<TKey, TValue>(v.Key, v.Value.Item1);
if (filter.IsMatch(value)) if (filter.IsMatch(value, v.Value.Item2))
{ {
filteredCount++; filteredCount++;
} }
@ -103,7 +103,7 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>>.Null; this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
this.filteredCount = dict.Count; this.filteredCount = dict.Count;
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<KeyValuePair<TKey, TValue>, TView>(NotifyCollectionChangedAction.Reset, true)); ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<KeyValuePair<TKey, TValue>, TView>(NotifyCollectionChangedAction.Reset, true));
} }
@ -131,7 +131,7 @@ namespace ObservableCollections
foreach (var item in dict) foreach (var item in dict)
{ {
var v = (new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2); var v = (new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2);
if (filter.IsMatch(v.Item1)) if (filter.IsMatch(v))
{ {
yield return v.Item2; yield return v.Item2;
} }
@ -150,7 +150,7 @@ namespace ObservableCollections
foreach (var item in dict) foreach (var item in dict)
{ {
var v = (new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2); var v = (new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2);
if (filter.IsMatch(v.Item1)) if (filter.IsMatch(v))
{ {
yield return v; yield return v;
} }

View File

@ -17,7 +17,7 @@ namespace ObservableCollections
sealed class View<TView> : ISynchronizedView<T, TView> sealed class View<TView> : ISynchronizedView<T, TView>
{ {
public ISynchronizedViewFilter<T> Filter public ISynchronizedViewFilter<T, TView> Filter
{ {
get { lock (SyncRoot) return filter; } get { lock (SyncRoot) return filter; }
} }
@ -27,7 +27,7 @@ namespace ObservableCollections
readonly Dictionary<T, (T, TView)> dict; readonly Dictionary<T, (T, TView)> dict;
int filteredCount; int filteredCount;
ISynchronizedViewFilter<T> filter; ISynchronizedViewFilter<T, TView> filter;
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged; public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged; public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
@ -39,7 +39,7 @@ namespace ObservableCollections
{ {
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.filter = SynchronizedViewFilter<T>.Null; this.filter = SynchronizedViewFilter<T, TView>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
@ -71,7 +71,7 @@ namespace ObservableCollections
} }
} }
public void AttachFilter(ISynchronizedViewFilter<T> filter) public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
{ {
if (filter.IsNullFilter()) if (filter.IsNullFilter())
{ {
@ -85,7 +85,7 @@ namespace ObservableCollections
this.filteredCount = 0; this.filteredCount = 0;
foreach (var (_, (value, view)) in dict) foreach (var (_, (value, view)) in dict)
{ {
if (filter.IsMatch(value)) if (filter.IsMatch(value, view))
{ {
filteredCount++; filteredCount++;
} }
@ -98,7 +98,7 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T>.Null; this.filter = SynchronizedViewFilter<T, TView>.Null;
this.filteredCount = dict.Count; this.filteredCount = dict.Count;
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset, true)); ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset, true));
} }
@ -125,7 +125,7 @@ namespace ObservableCollections
{ {
foreach (var item in dict) foreach (var item in dict)
{ {
if (filter.IsMatch(item.Value.Item1)) if (filter.IsMatch(item.Value))
{ {
yield return item.Value.Item2; yield return item.Value.Item2;
} }
@ -143,7 +143,7 @@ namespace ObservableCollections
{ {
foreach (var item in dict) foreach (var item in dict)
{ {
if (filter.IsMatch(item.Value.Item1)) if (filter.IsMatch(item.Value))
{ {
yield return item.Value; yield return item.Value;
} }

View File

@ -48,7 +48,7 @@ namespace ObservableCollections
internal sealed class View<TView> : ISynchronizedView<T, TView>, IWritableSynchronizedView<T, TView> internal sealed class View<TView> : ISynchronizedView<T, TView>, IWritableSynchronizedView<T, TView>
{ {
public ISynchronizedViewFilter<T> Filter public ISynchronizedViewFilter<T, TView> Filter
{ {
get get
{ {
@ -61,7 +61,7 @@ namespace ObservableCollections
internal readonly List<(T, TView)> list; // unsafe, be careful to use internal readonly List<(T, TView)> list; // unsafe, be careful to use
int filteredCount; int filteredCount;
ISynchronizedViewFilter<T> filter; ISynchronizedViewFilter<T, TView> filter;
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged; public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged; public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
@ -73,7 +73,7 @@ namespace ObservableCollections
{ {
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.filter = SynchronizedViewFilter<T>.Null; this.filter = SynchronizedViewFilter<T, TView>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
@ -105,7 +105,7 @@ namespace ObservableCollections
} }
} }
public void AttachFilter(ISynchronizedViewFilter<T> filter) public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
{ {
if (filter.IsNullFilter()) if (filter.IsNullFilter())
{ {
@ -119,7 +119,7 @@ namespace ObservableCollections
this.filteredCount = 0; this.filteredCount = 0;
for (var i = 0; i < list.Count; i++) for (var i = 0; i < list.Count; i++)
{ {
if (filter.IsMatch(list[i].Item1)) if (filter.IsMatch(list[i]))
{ {
filteredCount++; filteredCount++;
} }
@ -133,7 +133,7 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T>.Null; this.filter = SynchronizedViewFilter<T, TView>.Null;
this.filteredCount = list.Count; this.filteredCount = list.Count;
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset, true)); ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset, true));
} }
@ -160,7 +160,7 @@ namespace ObservableCollections
{ {
foreach (var item in list) foreach (var item in list)
{ {
if (filter.IsMatch(item.Item1)) if (filter.IsMatch(item))
{ {
yield return item.Item2; yield return item.Item2;
} }
@ -178,7 +178,7 @@ namespace ObservableCollections
{ {
foreach (var item in list) foreach (var item in list)
{ {
if (filter.IsMatch(item.Item1)) if (filter.IsMatch(item))
{ {
yield return item; yield return item;
} }
@ -235,7 +235,7 @@ namespace ObservableCollections
var view = selector(item); var view = selector(item);
views.Span[i] = view; views.Span[i] = view;
valueViews.Span[i] = (item, view); valueViews.Span[i] = (item, view);
var isMatch = matches.Span[i] = Filter.IsMatch(item); var isMatch = matches.Span[i] = Filter.IsMatch(item, view);
if (isMatch) if (isMatch)
{ {
filteredCount++; // increment in this process filteredCount++; // increment in this process
@ -271,7 +271,7 @@ namespace ObservableCollections
var item = list[i]; var item = list[i];
values.Span[j] = item.Item1; values.Span[j] = item.Item1;
views.Span[j] = item.Item2; views.Span[j] = item.Item2;
var isMatch = matches.Span[j] = Filter.IsMatch(item.Item1); var isMatch = matches.Span[j] = Filter.IsMatch(item);
if (isMatch) if (isMatch)
{ {
filteredCount--; // decrement in this process filteredCount--; // decrement in this process

View File

@ -22,7 +22,7 @@ namespace ObservableCollections
protected readonly Queue<(T, TView)> queue; protected readonly Queue<(T, TView)> queue;
int filteredCount; int filteredCount;
ISynchronizedViewFilter<T> filter; ISynchronizedViewFilter<T, TView> filter;
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged; public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged; public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
@ -30,7 +30,7 @@ namespace ObservableCollections
public object SyncRoot { get; } public object SyncRoot { get; }
public ISynchronizedViewFilter<T> Filter public ISynchronizedViewFilter<T, TView> Filter
{ {
get { lock (SyncRoot) return filter; } get { lock (SyncRoot) return filter; }
} }
@ -39,7 +39,7 @@ namespace ObservableCollections
{ {
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.filter = SynchronizedViewFilter<T>.Null; this.filter = SynchronizedViewFilter<T, TView>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
@ -71,7 +71,7 @@ namespace ObservableCollections
} }
} }
public void AttachFilter(ISynchronizedViewFilter<T> filter) public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
{ {
if (filter.IsNullFilter()) if (filter.IsNullFilter())
{ {
@ -85,7 +85,7 @@ namespace ObservableCollections
this.filteredCount = 0; this.filteredCount = 0;
foreach (var (value, view) in queue) foreach (var (value, view) in queue)
{ {
if (filter.IsMatch(value)) if (filter.IsMatch(value, view))
{ {
filteredCount++; filteredCount++;
} }
@ -98,7 +98,7 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T>.Null; this.filter = SynchronizedViewFilter<T, TView>.Null;
this.filteredCount = queue.Count; this.filteredCount = queue.Count;
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset, true)); ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset, true));
} }
@ -125,7 +125,7 @@ namespace ObservableCollections
{ {
foreach (var item in queue) foreach (var item in queue)
{ {
if (filter.IsMatch(item.Item1)) if (filter.IsMatch(item))
{ {
yield return item.Item2; yield return item.Item2;
} }
@ -143,7 +143,7 @@ namespace ObservableCollections
{ {
foreach (var item in queue) foreach (var item in queue)
{ {
if (filter.IsMatch(item.Item1)) if (filter.IsMatch(item))
{ {
yield return item; yield return item;
} }

View File

@ -18,7 +18,7 @@ namespace ObservableCollections
// used with ObservableFixedSizeRingBuffer // used with ObservableFixedSizeRingBuffer
internal sealed class View<TView> : ISynchronizedView<T, TView> internal sealed class View<TView> : ISynchronizedView<T, TView>
{ {
public ISynchronizedViewFilter<T> Filter public ISynchronizedViewFilter<T, TView> Filter
{ {
get { lock (SyncRoot) return filter; } get { lock (SyncRoot) return filter; }
} }
@ -28,7 +28,7 @@ namespace ObservableCollections
readonly RingBuffer<(T, TView)> ringBuffer; readonly RingBuffer<(T, TView)> ringBuffer;
int filteredCount; int filteredCount;
ISynchronizedViewFilter<T> filter; ISynchronizedViewFilter<T, TView> filter;
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged; public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged; public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
@ -40,7 +40,7 @@ namespace ObservableCollections
{ {
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.filter = SynchronizedViewFilter<T>.Null; this.filter = SynchronizedViewFilter<T, TView>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
@ -72,7 +72,7 @@ namespace ObservableCollections
} }
} }
public void AttachFilter(ISynchronizedViewFilter<T> filter) public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
{ {
if (filter.IsNullFilter()) if (filter.IsNullFilter())
{ {
@ -87,7 +87,7 @@ namespace ObservableCollections
for (var i = 0; i < ringBuffer.Count; i++) for (var i = 0; i < ringBuffer.Count; i++)
{ {
var (value, view) = ringBuffer[i]; var (value, view) = ringBuffer[i];
if (filter.IsMatch(value)) if (filter.IsMatch(value, view))
{ {
filteredCount++; filteredCount++;
} }
@ -100,7 +100,7 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T>.Null; this.filter = SynchronizedViewFilter<T, TView>.Null;
this.filteredCount = ringBuffer.Count; this.filteredCount = ringBuffer.Count;
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset, true)); ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset, true));
} }
@ -133,7 +133,7 @@ namespace ObservableCollections
{ {
foreach (var item in ringBuffer) foreach (var item in ringBuffer)
{ {
if (filter.IsMatch(item.Item1)) if (filter.IsMatch(item))
{ {
yield return item.Item2; yield return item.Item2;
} }
@ -151,7 +151,7 @@ namespace ObservableCollections
{ {
foreach (var item in ringBuffer) foreach (var item in ringBuffer)
{ {
if (filter.IsMatch(item.Item1)) if (filter.IsMatch(item))
{ {
yield return item; yield return item;
} }

View File

@ -21,7 +21,7 @@ namespace ObservableCollections
protected readonly Stack<(T, TView)> stack; protected readonly Stack<(T, TView)> stack;
int filteredCount; int filteredCount;
ISynchronizedViewFilter<T> filter; ISynchronizedViewFilter<T, TView> filter;
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged; public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged; public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
@ -29,7 +29,7 @@ namespace ObservableCollections
public object SyncRoot { get; } public object SyncRoot { get; }
public ISynchronizedViewFilter<T> Filter public ISynchronizedViewFilter<T, TView> Filter
{ {
get { lock (SyncRoot) return filter; } get { lock (SyncRoot) return filter; }
} }
@ -38,7 +38,7 @@ namespace ObservableCollections
{ {
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.filter = SynchronizedViewFilter<T>.Null; this.filter = SynchronizedViewFilter<T, TView>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
@ -70,7 +70,7 @@ namespace ObservableCollections
} }
} }
public void AttachFilter(ISynchronizedViewFilter<T> filter) public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
{ {
if (filter.IsNullFilter()) if (filter.IsNullFilter())
{ {
@ -84,7 +84,7 @@ namespace ObservableCollections
this.filteredCount = 0; this.filteredCount = 0;
foreach (var (value, view) in stack) foreach (var (value, view) in stack)
{ {
if (filter.IsMatch(value)) if (filter.IsMatch(value, view))
{ {
filteredCount++; filteredCount++;
} }
@ -97,7 +97,7 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T>.Null; this.filter = SynchronizedViewFilter<T, TView>.Null;
this.filteredCount = stack.Count; this.filteredCount = stack.Count;
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset, true)); ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset, true));
} }
@ -130,7 +130,7 @@ namespace ObservableCollections
{ {
foreach (var item in stack) foreach (var item in stack)
{ {
if (filter.IsMatch(item.Item1)) if (filter.IsMatch(item))
{ {
yield return item.Item2; yield return item.Item2;
} }
@ -148,7 +148,7 @@ namespace ObservableCollections
{ {
foreach (var item in stack) foreach (var item in stack)
{ {
if (filter.IsMatch(item.Item1)) if (filter.IsMatch(item))
{ {
yield return item; yield return item;
} }

View File

@ -86,12 +86,22 @@ namespace ObservableCollections
{ {
public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, bool> filter) public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, bool> filter)
{ {
source.AttachFilter(new SynchronizedViewFilter<T>(filter)); source.AttachFilter(new SynchronizedViewValueOnlyFilter<T, TView>(filter));
} }
public static bool IsNullFilter<T>(this ISynchronizedViewFilter<T> filter) public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, TView, bool> filter)
{ {
return filter == SynchronizedViewFilter<T>.Null; source.AttachFilter(new SynchronizedViewFilter<T, TView>(filter));
}
public static bool IsNullFilter<T, TView>(this ISynchronizedViewFilter<T, TView> filter)
{
return filter == SynchronizedViewFilter<T, TView>.Null;
}
internal static bool IsMatch<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T, TView) item)
{
return filter.IsMatch(item.Item1, item.Item2);
} }
internal static void InvokeOnAdd<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, Action<RejectedViewChangedAction, int, int>? ev2, (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, Action<RejectedViewChangedAction, int, int>? ev2, (T value, TView view) value, int index)
@ -101,7 +111,7 @@ namespace ObservableCollections
internal static void InvokeOnAdd<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, Action<RejectedViewChangedAction, int, int>? ev2, T value, TView view, int index) internal static void InvokeOnAdd<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, Action<RejectedViewChangedAction, int, int>? ev2, T value, TView view, int index)
{ {
var isMatch = collection.Filter.IsMatch(value); var isMatch = collection.Filter.IsMatch(value, view);
if (isMatch) if (isMatch)
{ {
filteredCount++; filteredCount++;
@ -144,7 +154,7 @@ namespace ObservableCollections
internal static void InvokeOnRemove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, Action<RejectedViewChangedAction, int, int>? ev2, T value, TView view, int oldIndex) internal static void InvokeOnRemove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, Action<RejectedViewChangedAction, int, int>? ev2, T value, TView view, int oldIndex)
{ {
var isMatch = collection.Filter.IsMatch(value); var isMatch = collection.Filter.IsMatch(value, view);
if (isMatch) if (isMatch)
{ {
filteredCount--; filteredCount--;
@ -188,7 +198,7 @@ namespace ObservableCollections
internal static void InvokeOnMove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, Action<RejectedViewChangedAction, int, int>? ev2, 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, Action<RejectedViewChangedAction, int, int>? ev2, T value, TView view, int index, int oldIndex)
{ {
// move does not changes filtered-count // move does not changes filtered-count
var isMatch = collection.Filter.IsMatch(value); var isMatch = collection.Filter.IsMatch(value, view);
if (isMatch) if (isMatch)
{ {
ev?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Move, true, newItem: (value, view), newStartingIndex: index, oldStartingIndex: oldIndex)); ev?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Move, true, newItem: (value, view), newStartingIndex: index, oldStartingIndex: oldIndex));
@ -206,8 +216,8 @@ namespace ObservableCollections
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) 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 oldMatched = collection.Filter.IsMatch(oldValue, oldView);
var newMatched = collection.Filter.IsMatch(value); var newMatched = collection.Filter.IsMatch(value, view);
var bothMatched = oldMatched && newMatched; var bothMatched = oldMatched && newMatched;
if (bothMatched) if (bothMatched)

View File

@ -54,7 +54,7 @@ internal sealed class FiltableSynchronizedViewList<T, TView> : NotifyCollectionC
{ {
foreach (var item in parent.Unfiltered) // use Unfiltered foreach (var item in parent.Unfiltered) // use Unfiltered
{ {
if (filter.IsMatch(item.Value)) if (filter.IsMatch(item))
{ {
yield return (index, item.View); yield return (index, item.View);
} }