more interface change
This commit is contained in:
parent
abed307158
commit
68618fda10
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetFilter(Action<T>? resetAction)
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user