From 4aacf11beeb77f9d393a70a7e335fdbf1d8aec65 Mon Sep 17 00:00:00 2001 From: neuecc Date: Wed, 21 Aug 2024 17:00:28 +0900 Subject: [PATCH] WIP --- .../IObservableCollection.cs | 12 +- .../ISynchronizedViewFilter.cs | 152 ++++++++++-------- ...NotifyCollectionChangedSynchronizedView.cs | 27 ++-- .../ObservableList.Views.cs | 9 +- 4 files changed, 106 insertions(+), 94 deletions(-) diff --git a/src/ObservableCollections/IObservableCollection.cs b/src/ObservableCollections/IObservableCollection.cs index b17a30c..108fab8 100644 --- a/src/ObservableCollections/IObservableCollection.cs +++ b/src/ObservableCollections/IObservableCollection.cs @@ -21,7 +21,7 @@ namespace ObservableCollections { } - public interface IReadOnlyObservableDictionary : + public interface IReadOnlyObservableDictionary : IReadOnlyDictionary, IObservableCollection> { } @@ -35,16 +35,16 @@ namespace ObservableCollections public interface ISynchronizedView : IReadOnlyCollection<(T Value, TView View)>, IDisposable { object SyncRoot { get; } - ISynchronizedViewFilter CurrentFilter { get; } + ISynchronizedViewFilter CurrentFilter { get; } // TODO: add - event Action>? ViewChanged; + event Action>? ViewChanged; // TODO: remove - event NotifyCollectionChangedEventHandler? RoutingCollectionChanged; + // event NotifyCollectionChangedEventHandler? RoutingCollectionChanged; event Action? CollectionStateChanged; - void AttachFilter(ISynchronizedViewFilter filter, bool invokeAddEventForInitialElements = false); - void ResetFilter(Action? resetAction); + void AttachFilter(ISynchronizedViewFilter filter, bool invokeAddEventForInitialElements = false); + void ResetFilter(Action? resetAction); INotifyCollectionChangedSynchronizedView ToNotifyCollectionChanged(); INotifyCollectionChangedSynchronizedView ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher); } diff --git a/src/ObservableCollections/ISynchronizedViewFilter.cs b/src/ObservableCollections/ISynchronizedViewFilter.cs index a2daec2..9f4b32b 100644 --- a/src/ObservableCollections/ISynchronizedViewFilter.cs +++ b/src/ObservableCollections/ISynchronizedViewFilter.cs @@ -21,111 +21,130 @@ namespace ObservableCollections public readonly int OldViewIndex = oldViewIndex; } - public interface ISynchronizedViewFilter + public interface ISynchronizedViewFilter { - bool IsMatch(T value, TView view); - void WhenTrue(T value, TView view); - void WhenFalse(T value, TView view); - void OnCollectionChanged(in SynchronizedViewChangedEventArgs eventArgs); + bool IsMatch(T value); } - public class SynchronizedViewFilter( - Func isMatch, - Action? whenTrue, - Action? whenFalse, - Action>? onCollectionChanged) - : ISynchronizedViewFilter + public class SynchronizedViewFilter(Func isMatch) : ISynchronizedViewFilter { - public static readonly ISynchronizedViewFilter Null = new NullViewFilter(); + public static readonly ISynchronizedViewFilter 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 eventArgs) => onCollectionChanged?.Invoke(eventArgs); + public bool IsMatch(T value) => isMatch(value); - class NullViewFilter : ISynchronizedViewFilter + class NullViewFilter : ISynchronizedViewFilter { - 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 eventArgs) { } + public bool IsMatch(T value) => true; } } public static class SynchronizedViewFilterExtensions { - public static void AttachFilter(this ISynchronizedView source, Func filter) + public static void AttachFilter(this ISynchronizedView source, Func filter) { - source.AttachFilter(new SynchronizedViewFilter(filter, null, null, null)); + source.AttachFilter(new SynchronizedViewFilter(filter)); } - public static void AttachFilter(this ISynchronizedView source, Func isMatch, Action? whenTrue, Action? whenFalse) + public static bool IsNullFilter(this ISynchronizedViewFilter filter) { - source.AttachFilter(new SynchronizedViewFilter(isMatch, whenTrue, whenFalse, null)); + return filter == SynchronizedViewFilter.Null; } - public static void AttachFilter(this ISynchronizedView source, Func isMatch, Action? whenTrue, Action? whenFalse, Action>? onCollectionChanged) + internal static void InvokeOnAdd(this ISynchronizedView collection, ref int filteredCount, Action>? ev, (T value, TView view) value, int index) { - source.AttachFilter(new SynchronizedViewFilter(isMatch, whenTrue, whenFalse, onCollectionChanged)); + InvokeOnAdd(collection, ref filteredCount, ev, value.value, value.view, index); } - public static bool IsNullFilter(this ISynchronizedViewFilter filter) + internal static void InvokeOnAdd(this ISynchronizedView collection, ref int filteredCount, Action>? ev, T value, TView view, int index) { - return filter == SynchronizedViewFilter.Null; - } - - - internal static void InvokeOnAdd(this ISynchronizedViewFilter filter, (T value, TView view) value, int index) - { - filter.InvokeOnAdd(value.value, value.view, index); - } - - internal static void InvokeOnAdd(this ISynchronizedViewFilter 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(NotifyCollectionChangedAction.Add, newValue: value, newView: view, newViewIndex: index)); + } } - else + } + + internal static void InvokeOnRemove(this ISynchronizedView collection, ref int filteredCount, Action>? ev, (T value, TView view) value, int oldIndex) + { + InvokeOnRemove(collection, ref filteredCount, ev, value.value, value.view, oldIndex); + } + + internal static void InvokeOnRemove(this ISynchronizedView collection, ref int filteredCount, Action>? 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(NotifyCollectionChangedAction.Remove, isMatch, oldValue: value, oldView: view, oldViewIndex: oldIndex)); + } } - filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs(NotifyCollectionChangedAction.Add, newValue: value, newView: view, newViewIndex: index)); } - internal static void InvokeOnRemove(this ISynchronizedViewFilter filter, (T value, TView view) value, int oldIndex) + internal static void InvokeOnMove(this ISynchronizedView collection, ref int filteredCount, Action>? 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(this ISynchronizedViewFilter filter, T value, TView view, int oldIndex) + internal static void InvokeOnMove(this ISynchronizedView collection, ref int filteredCount, Action>? ev, T value, TView view, int index, int oldIndex) { - filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs(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(NotifyCollectionChangedAction.Move, newValue: value, newView: view, newViewIndex: index, oldViewIndex: oldIndex)); + } + } } - internal static void InvokeOnMove(this ISynchronizedViewFilter filter, (T value, TView view) value, int index, int oldIndex) + internal static void InvokeOnReplace(this ISynchronizedView collection, ref int filteredCount, Action>? 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(this ISynchronizedViewFilter filter, T value, TView view, int index, int oldIndex) + internal static void InvokeOnReplace(this ISynchronizedView collection, ref int filteredCount, Action>? ev, T value, TView view, T oldValue, TView oldView, int index, int oldIndex = -1) { - filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs(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(NotifyCollectionChangedAction.Replace, isMatch, newValue: value, newView: view, oldValue: oldValue, oldView: oldView, newViewIndex: index, oldViewIndex: oldIndex >= 0 ? oldIndex : index)); + } } - internal static void InvokeOnReplace(this ISynchronizedViewFilter filter, (T value, TView view) value, (T value, TView view) oldValue, int index, int oldIndex = -1) + internal static void InvokeOnReset(this ISynchronizedView collection, ref int filteredCount, Action>? ev) { - filter.InvokeOnReplace(value.value, value.view, oldValue.value, oldValue.view, index, oldIndex); - } - - internal static void InvokeOnReplace(this ISynchronizedViewFilter filter, T value, TView view, T oldValue, TView oldView, int index, int oldIndex = -1) - { - filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs(NotifyCollectionChangedAction.Replace, newValue: value, newView: view, oldValue: oldValue, oldView: oldView, newViewIndex: index, oldViewIndex: oldIndex >= 0 ? oldIndex : index)); - } - - internal static void InvokeOnReset(this ISynchronizedViewFilter filter) - { - filter.OnCollectionChanged(new SynchronizedViewChangedEventArgs(NotifyCollectionChangedAction.Reset)); + filteredCount = 0; + if (ev != null) + { + ev.Invoke(new SynchronizedViewChangedEventArgs(NotifyCollectionChangedAction.Reset, true)); + } } internal static void InvokeOnAttach(this ISynchronizedViewFilter filter, T value, TView view) @@ -139,10 +158,5 @@ namespace ObservableCollections filter.WhenFalse(value, view); } } - - internal static bool IsMatch(this ISynchronizedViewFilter filter, (T, TView) value) - { - return filter.IsMatch(value); - } } } diff --git a/src/ObservableCollections/Internal/NotifyCollectionChangedSynchronizedView.cs b/src/ObservableCollections/Internal/NotifyCollectionChangedSynchronizedView.cs index e6c4c3c..97a5251 100644 --- a/src/ObservableCollections/Internal/NotifyCollectionChangedSynchronizedView.cs +++ b/src/ObservableCollections/Internal/NotifyCollectionChangedSynchronizedView.cs @@ -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 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 GetEnumerator() { - throw new NotImplementedException(); + return listView.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { - throw new NotImplementedException(); + return listView.GetEnumerator(); + } + + public void Dispose() + { + parent.ViewChanged -= Parent_ViewChanged; } } diff --git a/src/ObservableCollections/ObservableList.Views.cs b/src/ObservableCollections/ObservableList.Views.cs index 549bbcb..eac67a2 100644 --- a/src/ObservableCollections/ObservableList.Views.cs +++ b/src/ObservableCollections/ObservableList.Views.cs @@ -32,7 +32,8 @@ namespace ObservableCollections ISynchronizedViewFilter filter; - public event NotifyCollectionChangedEventHandler? RoutingCollectionChanged; + public event Action>? ViewChanged; + // public event NotifyCollectionChangedEventHandler? RoutingCollectionChanged; public event Action? 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 {