WIP
This commit is contained in:
parent
ffa8a97e35
commit
4aacf11bee
@ -21,7 +21,7 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IReadOnlyObservableDictionary<TKey, TValue> :
|
public interface IReadOnlyObservableDictionary<TKey, TValue> :
|
||||||
IReadOnlyDictionary<TKey, TValue>, IObservableCollection<KeyValuePair<TKey, TValue>>
|
IReadOnlyDictionary<TKey, TValue>, IObservableCollection<KeyValuePair<TKey, TValue>>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -35,16 +35,16 @@ namespace ObservableCollections
|
|||||||
public interface ISynchronizedView<T, TView> : IReadOnlyCollection<(T Value, TView View)>, IDisposable
|
public interface ISynchronizedView<T, TView> : IReadOnlyCollection<(T Value, TView View)>, IDisposable
|
||||||
{
|
{
|
||||||
object SyncRoot { get; }
|
object SyncRoot { get; }
|
||||||
ISynchronizedViewFilter<T, TView> CurrentFilter { get; }
|
ISynchronizedViewFilter<T> CurrentFilter { get; }
|
||||||
|
|
||||||
// TODO: add
|
// TODO: add
|
||||||
event Action<SynchronizedViewChangedEventArgs<T,TView>>? ViewChanged;
|
event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
|
||||||
// TODO: remove
|
// TODO: remove
|
||||||
event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
// event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
||||||
event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||||
|
|
||||||
void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForInitialElements = false);
|
void AttachFilter(ISynchronizedViewFilter<T> filter, bool invokeAddEventForInitialElements = false);
|
||||||
void ResetFilter(Action<T, TView>? resetAction);
|
void ResetFilter(Action<T>? resetAction);
|
||||||
INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged();
|
INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged();
|
||||||
INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher);
|
INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher);
|
||||||
}
|
}
|
||||||
|
@ -21,111 +21,130 @@ namespace ObservableCollections
|
|||||||
public readonly int OldViewIndex = oldViewIndex;
|
public readonly int OldViewIndex = oldViewIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ISynchronizedViewFilter<T, TView>
|
public interface ISynchronizedViewFilter<T>
|
||||||
{
|
{
|
||||||
bool IsMatch(T value, TView view);
|
bool IsMatch(T value);
|
||||||
void WhenTrue(T value, TView view);
|
|
||||||
void WhenFalse(T value, TView view);
|
|
||||||
void OnCollectionChanged(in SynchronizedViewChangedEventArgs<T, TView> eventArgs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SynchronizedViewFilter<T, TView>(
|
public class SynchronizedViewFilter<T>(Func<T, bool> isMatch) : ISynchronizedViewFilter<T>
|
||||||
Func<T, TView, bool> isMatch,
|
|
||||||
Action<T, TView>? whenTrue,
|
|
||||||
Action<T, TView>? whenFalse,
|
|
||||||
Action<SynchronizedViewChangedEventArgs<T, TView>>? onCollectionChanged)
|
|
||||||
: ISynchronizedViewFilter<T, TView>
|
|
||||||
{
|
{
|
||||||
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 bool IsMatch(T value) => isMatch(value);
|
||||||
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);
|
|
||||||
|
|
||||||
class NullViewFilter : ISynchronizedViewFilter<T, TView>
|
class NullViewFilter : ISynchronizedViewFilter<T>
|
||||||
{
|
{
|
||||||
public bool IsMatch(T value, TView view) => true;
|
public bool IsMatch(T value) => true;
|
||||||
public void WhenFalse(T value, TView view) { }
|
|
||||||
public void WhenTrue(T value, TView view) { }
|
|
||||||
public void OnCollectionChanged(in SynchronizedViewChangedEventArgs<T, TView> eventArgs) { }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SynchronizedViewFilterExtensions
|
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;
|
var isMatch = collection.CurrentFilter.IsMatch(value);
|
||||||
}
|
if (isMatch)
|
||||||
|
|
||||||
|
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
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);
|
filteredCount = 0;
|
||||||
}
|
if (ev != null)
|
||||||
|
{
|
||||||
internal static void InvokeOnReplace<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, T oldValue, TView oldView, int index, int oldIndex = -1)
|
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset, true));
|
||||||
{
|
}
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void InvokeOnAttach<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view)
|
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);
|
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;
|
||||||
using System.Buffers;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
@ -16,6 +15,7 @@ namespace ObservableCollections.Internal
|
|||||||
public SynchronizedViewList(ISynchronizedView<T, TView> parent)
|
public SynchronizedViewList(ISynchronizedView<T, TView> parent)
|
||||||
{
|
{
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
this.listView = parent.Select(x => x.View).ToList(); // need lock
|
||||||
// TODO:add
|
// TODO:add
|
||||||
parent.ViewChanged += Parent_ViewChanged;
|
parent.ViewChanged += Parent_ViewChanged;
|
||||||
}
|
}
|
||||||
@ -24,7 +24,6 @@ namespace ObservableCollections.Internal
|
|||||||
{
|
{
|
||||||
// event is called inside lock(parent.SyncRoot)
|
// event is called inside lock(parent.SyncRoot)
|
||||||
// TODO: invoke in ICollectionEventDispatcher?
|
// TODO: invoke in ICollectionEventDispatcher?
|
||||||
|
|
||||||
switch (e.Action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
case NotifyCollectionChangedAction.Add: // Add or Insert
|
case NotifyCollectionChangedAction.Add: // Add or Insert
|
||||||
@ -50,6 +49,8 @@ namespace ObservableCollections.Internal
|
|||||||
case NotifyCollectionChangedAction.Replace: // Indexer
|
case NotifyCollectionChangedAction.Replace: // Indexer
|
||||||
if (e.NewViewIndex == -1)
|
if (e.NewViewIndex == -1)
|
||||||
{
|
{
|
||||||
|
var index = listView.IndexOf(e.OldView);
|
||||||
|
listView[index] = e.NewView;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -60,6 +61,7 @@ namespace ObservableCollections.Internal
|
|||||||
case NotifyCollectionChangedAction.Move: //Remove and Insert
|
case NotifyCollectionChangedAction.Move: //Remove and Insert
|
||||||
if (e.NewViewIndex == -1)
|
if (e.NewViewIndex == -1)
|
||||||
{
|
{
|
||||||
|
// do nothing
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -68,32 +70,31 @@ namespace ObservableCollections.Internal
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Reset: // Clear
|
case NotifyCollectionChangedAction.Reset: // Clear
|
||||||
|
listView.Clear();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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 int Count => listView.Count;
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<TView> GetEnumerator()
|
public IEnumerator<TView> GetEnumerator()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return listView.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.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;
|
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 event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||||
|
|
||||||
public object SyncRoot { get; }
|
public object SyncRoot { get; }
|
||||||
@ -162,11 +163,7 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
var v = (e.NewItem, selector(e.NewItem));
|
var v = (e.NewItem, selector(e.NewItem));
|
||||||
list.Add(v);
|
list.Add(v);
|
||||||
if (filter.IsMatch(v))
|
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, e.NewStartingIndex);
|
||||||
{
|
|
||||||
filteredCount++;
|
|
||||||
}
|
|
||||||
filter.InvokeOnAdd(v, e.NewStartingIndex);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user