This commit is contained in:
neuecc 2024-08-21 17:00:28 +09:00
parent ffa8a97e35
commit 4aacf11bee
4 changed files with 106 additions and 94 deletions

View File

@ -35,16 +35,16 @@ namespace ObservableCollections
public interface ISynchronizedView<T, TView> : IReadOnlyCollection<(T Value, TView View)>, IDisposable
{
object SyncRoot { get; }
ISynchronizedViewFilter<T, TView> CurrentFilter { get; }
ISynchronizedViewFilter<T> CurrentFilter { get; }
// TODO: add
event Action<SynchronizedViewChangedEventArgs<T,TView>>? ViewChanged;
event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
// TODO: remove
event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
// event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForInitialElements = false);
void ResetFilter(Action<T, TView>? resetAction);
void AttachFilter(ISynchronizedViewFilter<T> filter, bool invokeAddEventForInitialElements = false);
void ResetFilter(Action<T>? resetAction);
INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged();
INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher);
}

View File

@ -21,111 +21,130 @@ namespace ObservableCollections
public readonly int OldViewIndex = oldViewIndex;
}
public interface ISynchronizedViewFilter<T, TView>
public interface ISynchronizedViewFilter<T>
{
bool IsMatch(T value, TView view);
void WhenTrue(T value, TView view);
void WhenFalse(T value, TView view);
void OnCollectionChanged(in SynchronizedViewChangedEventArgs<T, TView> eventArgs);
bool IsMatch(T value);
}
public class SynchronizedViewFilter<T, TView>(
Func<T, TView, bool> isMatch,
Action<T, TView>? whenTrue,
Action<T, TView>? whenFalse,
Action<SynchronizedViewChangedEventArgs<T, TView>>? onCollectionChanged)
: ISynchronizedViewFilter<T, TView>
public class SynchronizedViewFilter<T>(Func<T, bool> isMatch) : ISynchronizedViewFilter<T>
{
public static readonly ISynchronizedViewFilter<T, TView> Null = new NullViewFilter();
public static readonly ISynchronizedViewFilter<T> Null = new NullViewFilter();
public bool IsMatch(T value, TView view) => isMatch(value, view);
public void WhenFalse(T value, TView view) => whenFalse?.Invoke(value, view);
public void WhenTrue(T value, TView view) => whenTrue?.Invoke(value, view);
public void OnCollectionChanged(in SynchronizedViewChangedEventArgs<T, TView> eventArgs) => onCollectionChanged?.Invoke(eventArgs);
public bool IsMatch(T value) => isMatch(value);
class NullViewFilter : ISynchronizedViewFilter<T, TView>
class NullViewFilter : ISynchronizedViewFilter<T>
{
public bool IsMatch(T value, TView view) => true;
public void WhenFalse(T value, TView view) { }
public void WhenTrue(T value, TView view) { }
public void OnCollectionChanged(in SynchronizedViewChangedEventArgs<T, TView> eventArgs) { }
public bool IsMatch(T value) => true;
}
}
public static class SynchronizedViewFilterExtensions
{
public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, TView, bool> filter)
public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, bool> filter)
{
source.AttachFilter(new SynchronizedViewFilter<T, TView>(filter, null, null, null));
source.AttachFilter(new SynchronizedViewFilter<T>(filter));
}
public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, TView, bool> isMatch, Action<T, TView>? whenTrue, Action<T, TView>? whenFalse)
public static bool IsNullFilter<T>(this ISynchronizedViewFilter<T> filter)
{
source.AttachFilter(new SynchronizedViewFilter<T, TView>(isMatch, whenTrue, whenFalse, null));
return filter == SynchronizedViewFilter<T>.Null;
}
public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, TView, bool> isMatch, Action<T, TView>? whenTrue, Action<T, TView>? whenFalse, Action<SynchronizedViewChangedEventArgs<T, TView>>? onCollectionChanged)
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)
{
source.AttachFilter(new SynchronizedViewFilter<T, TView>(isMatch, whenTrue, whenFalse, onCollectionChanged));
InvokeOnAdd(collection, ref filteredCount, ev, value.value, value.view, index);
}
public static bool IsNullFilter<T, TView>(this ISynchronizedViewFilter<T, TView> filter)
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)
{
return filter == SynchronizedViewFilter<T, TView>.Null;
}
internal static void InvokeOnAdd<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, int index)
{
filter.InvokeOnAdd(value.value, value.view, index);
}
internal static void InvokeOnAdd<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, int index)
{
if (filter.IsMatch(value, view))
var isMatch = collection.CurrentFilter.IsMatch(value);
if (isMatch)
{
filter.WhenTrue(value, view);
filteredCount++;
if (ev != null)
{
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, newValue: value, newView: view, newViewIndex: index));
}
}
else
}
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)
{
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)
{
var isMatch = collection.CurrentFilter.IsMatch(value);
if (isMatch)
{
filter.WhenFalse(value, view);
filteredCount--;
if (ev != null)
{
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, isMatch, oldValue: value, oldView: view, oldViewIndex: oldIndex));
}
}
filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, newValue: value, newView: view, newViewIndex: index));
}
internal static void InvokeOnRemove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, int 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)
{
filter.InvokeOnRemove(value.value, value.view, oldIndex);
InvokeOnMove(collection, ref filteredCount, ev, value.value, value.view, index, oldIndex);
}
internal static void InvokeOnRemove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, int 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)
{
filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, oldValue: value, oldView: view, oldViewIndex: oldIndex));
if (ev != null)
{
// move does not changes filtered-count
var isMatch = collection.CurrentFilter.IsMatch(value);
if (isMatch)
{
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Move, newValue: value, newView: view, newViewIndex: index, oldViewIndex: oldIndex));
}
}
}
internal static void InvokeOnMove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, int index, int 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)
{
InvokeOnMove(filter, value.value, value.view, index, oldIndex);
InvokeOnReplace(collection, ref filteredCount, ev, value.value, value.view, oldValue.value, oldValue.view, index, oldIndex);
}
internal static void InvokeOnMove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, int index, int 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)
{
filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Move, newValue: value, newView: view, newViewIndex: index, oldViewIndex: oldIndex));
var oldMatched = collection.CurrentFilter.IsMatch(oldValue);
var newMatched = collection.CurrentFilter.IsMatch(value);
var bothMatched = oldMatched && newMatched;
// TODO:...!
if (bothMatched)
{
}
else if (oldMatched)
{
// only-old is remove
}
else if (newMatched)
{
// only-new is add
}
if (ev != null)
{
var isMatch = collection.CurrentFilter.IsMatch(value);
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Replace, isMatch, newValue: value, newView: view, oldValue: oldValue, oldView: oldView, newViewIndex: index, oldViewIndex: oldIndex >= 0 ? oldIndex : index));
}
}
internal static void InvokeOnReplace<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, (T value, TView view) oldValue, int index, int oldIndex = -1)
internal static void InvokeOnReset<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, Action<SynchronizedViewChangedEventArgs<T, TView>>? ev)
{
filter.InvokeOnReplace(value.value, value.view, oldValue.value, oldValue.view, index, oldIndex);
}
internal static void InvokeOnReplace<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, T oldValue, TView oldView, int index, int oldIndex = -1)
{
filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Replace, newValue: value, newView: view, oldValue: oldValue, oldView: oldView, newViewIndex: index, oldViewIndex: oldIndex >= 0 ? oldIndex : index));
}
internal static void InvokeOnReset<T, TView>(this ISynchronizedViewFilter<T, TView> filter)
{
filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset));
filteredCount = 0;
if (ev != null)
{
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset, true));
}
}
internal static void InvokeOnAttach<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view)
@ -139,10 +158,5 @@ namespace ObservableCollections
filter.WhenFalse(value, view);
}
}
internal static bool IsMatch<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T, TView) value)
{
return filter.IsMatch(value);
}
}
}

View File

@ -1,5 +1,4 @@
using System;
using System.Buffers;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
@ -16,6 +15,7 @@ namespace ObservableCollections.Internal
public SynchronizedViewList(ISynchronizedView<T, TView> parent)
{
this.parent = parent;
this.listView = parent.Select(x => x.View).ToList(); // need lock
// TODO:add
parent.ViewChanged += Parent_ViewChanged;
}
@ -24,7 +24,6 @@ namespace ObservableCollections.Internal
{
// event is called inside lock(parent.SyncRoot)
// TODO: invoke in ICollectionEventDispatcher?
switch (e.Action)
{
case NotifyCollectionChangedAction.Add: // Add or Insert
@ -50,6 +49,8 @@ namespace ObservableCollections.Internal
case NotifyCollectionChangedAction.Replace: // Indexer
if (e.NewViewIndex == -1)
{
var index = listView.IndexOf(e.OldView);
listView[index] = e.NewView;
}
else
{
@ -60,6 +61,7 @@ namespace ObservableCollections.Internal
case NotifyCollectionChangedAction.Move: //Remove and Insert
if (e.NewViewIndex == -1)
{
// do nothing
}
else
{
@ -68,32 +70,31 @@ namespace ObservableCollections.Internal
}
break;
case NotifyCollectionChangedAction.Reset: // Clear
listView.Clear();
break;
default:
break;
}
// throw new NotImplementedException();
}
public TView this[int index] => throw new NotImplementedException();
public TView this[int index] => listView[index];
public int Count => throw new NotImplementedException();
public void Dispose()
{
throw new NotImplementedException();
}
public int Count => listView.Count;
public IEnumerator<TView> GetEnumerator()
{
throw new NotImplementedException();
return listView.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
return listView.GetEnumerator();
}
public void Dispose()
{
parent.ViewChanged -= Parent_ViewChanged;
}
}

View File

@ -32,7 +32,8 @@ namespace ObservableCollections
ISynchronizedViewFilter<T, TView> filter;
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
public event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
// public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public object SyncRoot { get; }
@ -162,11 +163,7 @@ namespace ObservableCollections
{
var v = (e.NewItem, selector(e.NewItem));
list.Add(v);
if (filter.IsMatch(v))
{
filteredCount++;
}
filter.InvokeOnAdd(v, e.NewStartingIndex);
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, e.NewStartingIndex);
}
else
{