more interface change

This commit is contained in:
neuecc 2024-08-23 17:09:32 +09:00
parent abed307158
commit 68618fda10
4 changed files with 59 additions and 44 deletions

View File

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

View File

@ -4,7 +4,7 @@ using System.Collections.Specialized;
namespace ObservableCollections namespace ObservableCollections
{ {
public readonly struct SynchronizedViewChangedEventArgs<T, TView>( public readonly struct SynchronizedViewChangedEventArgs<T, TView>(
NotifyCollectionChangedAction action, NotifyViewChangedAction action,
T newValue = default!, T newValue = default!,
T oldValue = default!, T oldValue = default!,
TView newView = default!, TView newView = default!,
@ -12,7 +12,7 @@ namespace ObservableCollections
int newViewIndex = -1, int newViewIndex = -1,
int oldViewIndex = -1) int oldViewIndex = -1)
{ {
public readonly NotifyCollectionChangedAction Action = action; public readonly NotifyViewChangedAction Action = action;
public readonly T NewValue = newValue; public readonly T NewValue = newValue;
public readonly T OldValue = oldValue; public readonly T OldValue = oldValue;
public readonly TView NewView = newView; public readonly TView NewView = newView;
@ -21,6 +21,16 @@ namespace ObservableCollections
public readonly int OldViewIndex = oldViewIndex; public readonly int OldViewIndex = oldViewIndex;
} }
public enum NotifyViewChangedAction
{
Add = 0,
Remove = 1,
Replace = 2,
Move = 3,
Reset = 4,
FilterReset = 5,
}
public interface ISynchronizedViewFilter<T> public interface ISynchronizedViewFilter<T>
{ {
bool IsMatch(T value); bool IsMatch(T value);
@ -57,13 +67,13 @@ namespace ObservableCollections
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, Action<SynchronizedViewChangedEventArgs<T, TView>>? ev, T value, TView view, int index)
{ {
var isMatch = collection.CurrentFilter.IsMatch(value); var isMatch = collection.Filter.IsMatch(value);
if (isMatch) if (isMatch)
{ {
filteredCount++; filteredCount++;
if (ev != null) if (ev != null)
{ {
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, newValue: value, newView: view, newViewIndex: index)); ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.Add, newValue: value, newView: view, newViewIndex: index));
} }
} }
} }
@ -75,13 +85,13 @@ namespace ObservableCollections
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, Action<SynchronizedViewChangedEventArgs<T, TView>>? ev, T value, TView view, int oldIndex)
{ {
var isMatch = collection.CurrentFilter.IsMatch(value); var isMatch = collection.Filter.IsMatch(value);
if (isMatch) if (isMatch)
{ {
filteredCount--; filteredCount--;
if (ev != null) if (ev != null)
{ {
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, oldValue: value, oldView: view, oldViewIndex: oldIndex)); ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.Remove, oldValue: value, oldView: view, oldViewIndex: oldIndex));
} }
} }
} }
@ -96,10 +106,10 @@ namespace ObservableCollections
if (ev != null) if (ev != null)
{ {
// move does not changes filtered-count // move does not changes filtered-count
var isMatch = collection.CurrentFilter.IsMatch(value); var isMatch = collection.Filter.IsMatch(value);
if (isMatch) if (isMatch)
{ {
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Move, newValue: value, newView: view, newViewIndex: index, oldViewIndex: oldIndex)); ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.Move, newValue: value, newView: view, newViewIndex: index, oldViewIndex: oldIndex));
} }
} }
} }
@ -111,15 +121,15 @@ namespace ObservableCollections
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, Action<SynchronizedViewChangedEventArgs<T, TView>>? ev, T value, TView view, T oldValue, TView oldView, int index, int oldIndex = -1)
{ {
var oldMatched = collection.CurrentFilter.IsMatch(oldValue); var oldMatched = collection.Filter.IsMatch(oldValue);
var newMatched = collection.CurrentFilter.IsMatch(value); var newMatched = collection.Filter.IsMatch(value);
var bothMatched = oldMatched && newMatched; var bothMatched = oldMatched && newMatched;
if (bothMatched) if (bothMatched)
{ {
if (ev != null) if (ev != null)
{ {
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Replace, newValue: value, newView: view, oldValue: oldValue, oldView: oldView, newViewIndex: index, oldViewIndex: oldIndex >= 0 ? oldIndex : index)); ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.Replace, newValue: value, newView: view, oldValue: oldValue, oldView: oldView, newViewIndex: index, oldViewIndex: oldIndex >= 0 ? oldIndex : index));
} }
} }
else if (oldMatched) else if (oldMatched)
@ -128,7 +138,7 @@ namespace ObservableCollections
filteredCount--; filteredCount--;
if (ev != null) if (ev != null)
{ {
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, oldValue: value, oldView: view, oldViewIndex: oldIndex)); ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.Remove, oldValue: value, oldView: view, oldViewIndex: oldIndex));
} }
} }
@ -138,7 +148,7 @@ namespace ObservableCollections
filteredCount++; filteredCount++;
if (ev != null) if (ev != null)
{ {
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, newValue: value, newView: view, newViewIndex: index)); ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.Add, newValue: value, newView: view, newViewIndex: index));
} }
} }
} }
@ -148,7 +158,7 @@ namespace ObservableCollections
filteredCount = 0; filteredCount = 0;
if (ev != null) if (ev != null)
{ {
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset)); ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.Reset));
} }
} }
} }

View File

@ -26,7 +26,7 @@ namespace ObservableCollections.Internal
// TODO: invoke in ICollectionEventDispatcher? // TODO: invoke in ICollectionEventDispatcher?
switch (e.Action) switch (e.Action)
{ {
case NotifyCollectionChangedAction.Add: // Add or Insert case NotifyViewChangedAction.Add: // Add or Insert
if (e.NewViewIndex == -1) if (e.NewViewIndex == -1)
{ {
listView.Add(e.NewView); listView.Add(e.NewView);
@ -36,7 +36,7 @@ namespace ObservableCollections.Internal
listView.Insert(e.NewViewIndex, e.NewView); listView.Insert(e.NewViewIndex, e.NewView);
} }
break; break;
case NotifyCollectionChangedAction.Remove: // Remove case NotifyViewChangedAction.Remove: // Remove
if (e.OldViewIndex == -1) // can't gurantee correct remove if index is not provided if (e.OldViewIndex == -1) // can't gurantee correct remove if index is not provided
{ {
listView.Remove(e.OldView); listView.Remove(e.OldView);
@ -46,7 +46,7 @@ namespace ObservableCollections.Internal
listView.RemoveAt(e.OldViewIndex); listView.RemoveAt(e.OldViewIndex);
} }
break; break;
case NotifyCollectionChangedAction.Replace: // Indexer case NotifyViewChangedAction.Replace: // Indexer
if (e.NewViewIndex == -1) if (e.NewViewIndex == -1)
{ {
var index = listView.IndexOf(e.OldView); var index = listView.IndexOf(e.OldView);
@ -58,7 +58,7 @@ namespace ObservableCollections.Internal
} }
break; break;
case NotifyCollectionChangedAction.Move: //Remove and Insert case NotifyViewChangedAction.Move: //Remove and Insert
if (e.NewViewIndex == -1) if (e.NewViewIndex == -1)
{ {
// do nothing // do nothing
@ -69,9 +69,16 @@ namespace ObservableCollections.Internal
listView.Insert(e.NewViewIndex, e.NewView); listView.Insert(e.NewViewIndex, e.NewView);
} }
break; break;
case NotifyCollectionChangedAction.Reset: // Clear case NotifyViewChangedAction.Reset: // Clear
listView.Clear(); listView.Clear();
break; break;
case NotifyViewChangedAction.FilterReset:
listView.Clear();
foreach (var item in parent)
{
listView.Add(item.View);
}
break;
default: default:
break; break;
} }
@ -116,7 +123,7 @@ namespace ObservableCollections.Internal
{ {
this.parent = parent; this.parent = parent;
this.eventDispatcher = eventDispatcher ?? DirectCollectionEventDispatcher.Instance; this.eventDispatcher = eventDispatcher ?? DirectCollectionEventDispatcher.Instance;
currentFilter = parent.CurrentFilter; currentFilter = parent.Filter;
parent.AttachFilter(this); parent.AttachFilter(this);
} }

View File

@ -16,7 +16,7 @@ namespace ObservableCollections
internal sealed class View<TView> : ISynchronizedView<T, TView> internal sealed class View<TView> : ISynchronizedView<T, TView>
{ {
public ISynchronizedViewFilter<T> CurrentFilter public ISynchronizedViewFilter<T> Filter
{ {
get get
{ {
@ -63,38 +63,38 @@ namespace ObservableCollections
} }
} }
public void AttachFilter(ISynchronizedViewFilter<T> filter, bool invokeAddEventForCurrentElements = false) public void AttachFilter(ISynchronizedViewFilter<T> filter)
{ {
if (filter.IsNullFilter())
{
ResetFilter();
return;
}
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = filter; this.filter = filter;
this.filteredCount = 0;
for (var i = 0; i < list.Count; i++) for (var i = 0; i < list.Count; i++)
{ {
var (value, view) = list[i]; if (filter.IsMatch(list[i].Item1))
if (invokeAddEventForCurrentElements)
{ {
filter.InvokeOnAdd(value, view, i); filteredCount++;
}
else
{
filter.InvokeOnAttach(value, view);
}
}
} }
} }
public void ResetFilter(Action<T>? resetAction) ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
}
}
public void ResetFilter()
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T>.Null; this.filter = SynchronizedViewFilter<T>.Null;
if (resetAction != null) this.filteredCount = list.Count;
{ ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
foreach (var (item, view) in list)
{
resetAction(item, view);
}
}
} }
} }