WIP
This commit is contained in:
parent
ffa8a97e35
commit
4aacf11bee
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user