Fix (NotifyCollecitonChanged)SynchronizedViewList does not sync correcty when view is attached filter
This commit is contained in:
parent
b73a30c366
commit
0ce9b3a10e
@ -466,6 +466,11 @@ This is the interface for View:
|
||||
```csharp
|
||||
public delegate void NotifyViewChangedEventHandler<T, TView>(in SynchronizedViewChangedEventArgs<T, TView> e);
|
||||
|
||||
public enum RejectedViewChangedAction
|
||||
{
|
||||
Add, Remove, Move
|
||||
}
|
||||
|
||||
public interface ISynchronizedView<T, TView> : IReadOnlyCollection<TView>, IDisposable
|
||||
{
|
||||
object SyncRoot { get; }
|
||||
@ -475,6 +480,7 @@ public interface ISynchronizedView<T, TView> : IReadOnlyCollection<TView>, IDisp
|
||||
int UnfilteredCount { get; }
|
||||
|
||||
event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
|
||||
event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged; // int index, int oldIndex(when RejectedViewChangedAction is Move)
|
||||
event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||
|
||||
void AttachFilter(ISynchronizedViewFilter<T> filter);
|
||||
|
@ -8,68 +8,80 @@ using System.Collections.Generic;
|
||||
|
||||
|
||||
|
||||
var buffer = new ObservableList<int>(5);
|
||||
|
||||
// Queue <-> List Synchronization
|
||||
var queue = new ObservableQueue<int>();
|
||||
var view = buffer.CreateView(value => value);
|
||||
view.AttachFilter(value => value % 2 == 1); // when filtered, mismatch...!
|
||||
|
||||
queue.Enqueue(1);
|
||||
queue.Enqueue(10);
|
||||
queue.Enqueue(100);
|
||||
queue.Enqueue(1000);
|
||||
queue.Enqueue(10000);
|
||||
//{
|
||||
// INotifyCollectionChangedSynchronizedViewList created from ISynchronizedView with a filter.
|
||||
var collection = view.ToNotifyCollectionChanged();
|
||||
|
||||
using var view = queue.CreateView(x => x.ToString() + "$");
|
||||
// Not disposed here.
|
||||
//}
|
||||
|
||||
using var viewList = view.ToViewList();
|
||||
buffer.Insert(0, 1);
|
||||
buffer.Insert(0, 1);
|
||||
buffer.Insert(0, 2);
|
||||
buffer.Insert(0, 3);
|
||||
buffer.Insert(0, 5);
|
||||
buffer.RemoveAt(buffer.Count - 1);
|
||||
|
||||
Console.WriteLine(viewList[2]); // 100$
|
||||
buffer.Insert(0, 8);
|
||||
buffer.Insert(0, 13);
|
||||
|
||||
|
||||
view.ViewChanged += View_ViewChanged;
|
||||
buffer.Move(1, 5);
|
||||
|
||||
void View_ViewChanged(in SynchronizedViewChangedEventArgs<int, string> eventArgs)
|
||||
foreach (var item in view)
|
||||
{
|
||||
if (eventArgs.Action == NotifyCollectionChangedAction.Add)
|
||||
{
|
||||
// eventArgs.OldItem.View.
|
||||
}
|
||||
Console.WriteLine(item);
|
||||
}
|
||||
Console.WriteLine("---");
|
||||
|
||||
throw new NotImplementedException();
|
||||
foreach (var item in collection)
|
||||
{
|
||||
|
||||
Console.WriteLine(item);
|
||||
}
|
||||
|
||||
class ViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Value { get; set; } = default!;
|
||||
}
|
||||
|
||||
class HogeFilter : ISynchronizedViewFilter<int>
|
||||
{
|
||||
public bool IsMatch(int value)
|
||||
{
|
||||
return value % 2 == 0;
|
||||
}
|
||||
|
||||
public void OnCollectionChanged(in SynchronizedViewChangedEventArgs<int, ViewModel> eventArgs)
|
||||
{
|
||||
switch (eventArgs.Action)
|
||||
{
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
eventArgs.NewItem.View.Value += " Add";
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
eventArgs.OldItem.View.Value += " Remove";
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Move:
|
||||
eventArgs.NewItem.View.Value += $" Move {eventArgs.OldStartingIndex} {eventArgs.NewStartingIndex}";
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Replace:
|
||||
eventArgs.NewItem.View.Value += $" Replace {eventArgs.NewStartingIndex}";
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(eventArgs.Action), eventArgs.Action, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
//var buffer = new ObservableFixedSizeRingBuffer<int>(5);
|
||||
|
||||
//var view = buffer.CreateView(value => value);
|
||||
//view.AttachFilter(value => value % 2 == 1); // when filtered, mismatch...!
|
||||
|
||||
////{
|
||||
//// INotifyCollectionChangedSynchronizedViewList created from ISynchronizedView with a filter.
|
||||
//var collection = view.ToNotifyCollectionChanged();
|
||||
|
||||
//// Not disposed here.
|
||||
////}
|
||||
|
||||
//buffer.AddFirst(1);
|
||||
//buffer.AddFirst(1);
|
||||
//buffer.AddFirst(2);
|
||||
//buffer.AddFirst(3);
|
||||
//buffer.AddFirst(5);
|
||||
//buffer.AddFirst(8); // Argument out of range
|
||||
//buffer.AddFirst(13);
|
||||
|
||||
//foreach (var item in collection)
|
||||
//{
|
||||
// Console.WriteLine(item);
|
||||
//}
|
||||
|
||||
//Console.WriteLine("---");
|
||||
|
||||
//foreach (var item in view)
|
||||
//{
|
||||
// Console.WriteLine(item);
|
||||
//}
|
||||
|
||||
//Console.WriteLine("---");
|
||||
|
||||
//foreach (var item in buffer)
|
||||
//{
|
||||
// Console.WriteLine(item);
|
||||
//}
|
@ -3,7 +3,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
@ -24,7 +23,7 @@ public class AlternateIndexList<T> : IEnumerable<T>
|
||||
this.list = values.Select(x => new IndexedValue(x.OrderedAlternateIndex, x.Value)).ToList();
|
||||
}
|
||||
|
||||
void UpdateAlternateIndex(int startIndex, int incr)
|
||||
public void UpdateAlternateIndex(int startIndex, int incr)
|
||||
{
|
||||
var span = CollectionsMarshal.AsSpan(list);
|
||||
for (int i = startIndex; i < span.Length; i++)
|
||||
@ -80,11 +79,15 @@ public class AlternateIndexList<T> : IEnumerable<T>
|
||||
public int RemoveAt(int alternateIndex)
|
||||
{
|
||||
var index = list.BinarySearch(alternateIndex);
|
||||
if (index != -1)
|
||||
if (index >= 0)
|
||||
{
|
||||
list.RemoveAt(index);
|
||||
UpdateAlternateIndex(index, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Index was not found. AlternateIndex:" + alternateIndex);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
@ -124,6 +127,19 @@ public class AlternateIndexList<T> : IEnumerable<T>
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryReplaceAlternateIndex(int getAlternateIndex, int setAlternateIndex)
|
||||
{
|
||||
var index = list.BinarySearch(getAlternateIndex);
|
||||
if (index < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var span = CollectionsMarshal.AsSpan(list);
|
||||
span[index].AlternateIndex = setAlternateIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryReplaceByValue(T searchValue, T replaceValue, out int replacedIndex)
|
||||
{
|
||||
replacedIndex = list.FindIndex(x => EqualityComparer<T>.Default.Equals(x.Value, searchValue));
|
||||
|
@ -25,6 +25,11 @@ namespace ObservableCollections
|
||||
{
|
||||
}
|
||||
|
||||
public enum RejectedViewChangedAction
|
||||
{
|
||||
Add, Remove, Move
|
||||
}
|
||||
|
||||
public interface ISynchronizedView<T, TView> : IReadOnlyCollection<TView>, IDisposable
|
||||
{
|
||||
object SyncRoot { get; }
|
||||
@ -34,6 +39,7 @@ namespace ObservableCollections
|
||||
int UnfilteredCount { get; }
|
||||
|
||||
event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
|
||||
event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
|
||||
event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||
|
||||
void AttachFilter(ISynchronizedViewFilter<T> filter);
|
||||
|
@ -39,6 +39,7 @@ namespace ObservableCollections
|
||||
|
||||
public object SyncRoot { get; }
|
||||
public event NotifyViewChangedEventHandler<KeyValuePair<TKey, TValue>, TView>? ViewChanged;
|
||||
public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
|
||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||
|
||||
public ISynchronizedViewFilter<KeyValuePair<TKey, TValue>> Filter
|
||||
@ -184,14 +185,14 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = selector(e.NewItem);
|
||||
dict.Add(e.NewItem.Key, (e.NewItem.Value, v));
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, e.NewItem, v, -1);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, RejectedViewChanged, e.NewItem, v, -1);
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
{
|
||||
if (dict.Remove(e.OldItem.Key, out var v))
|
||||
{
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, e.OldItem, v.Item2, -1);
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, RejectedViewChanged, e.OldItem, v.Item2, -1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -30,6 +30,7 @@ namespace ObservableCollections
|
||||
ISynchronizedViewFilter<T> filter;
|
||||
|
||||
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
|
||||
public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
|
||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||
|
||||
public object SyncRoot { get; }
|
||||
@ -181,7 +182,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (e.NewItem, selector(e.NewItem));
|
||||
dict.Add(e.NewItem, v);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, -1);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, RejectedViewChanged, v, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -190,7 +191,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (item, selector(item));
|
||||
dict.Add(item, v);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, i++);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, RejectedViewChanged, v, i++);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -199,7 +200,7 @@ namespace ObservableCollections
|
||||
{
|
||||
if (dict.Remove(e.OldItem, out var value))
|
||||
{
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, value, -1);
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, RejectedViewChanged, value, -1);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -208,7 +209,7 @@ namespace ObservableCollections
|
||||
{
|
||||
if (dict.Remove(item, out var value))
|
||||
{
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, value, -1);
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, RejectedViewChanged, value, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ namespace ObservableCollections
|
||||
ISynchronizedViewFilter<T> filter;
|
||||
|
||||
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
|
||||
public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
|
||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||
|
||||
public object SyncRoot { get; }
|
||||
@ -185,7 +186,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (e.NewItem, selector(e.NewItem));
|
||||
list.Insert(e.NewStartingIndex, v);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, e.NewStartingIndex);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, RejectedViewChanged, v, e.NewStartingIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -214,7 +215,7 @@ namespace ObservableCollections
|
||||
}
|
||||
|
||||
list.InsertRange(e.NewStartingIndex, valueViews.Span);
|
||||
this.InvokeOnAddRange(ViewChanged, e.NewItems, views.Span, isMatchAll, matches.Span, e.NewStartingIndex);
|
||||
this.InvokeOnAddRange(ViewChanged, RejectedViewChanged, e.NewItems, views.Span, isMatchAll, matches.Span, e.NewStartingIndex);
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
@ -222,7 +223,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = list[e.OldStartingIndex];
|
||||
list.RemoveAt(e.OldStartingIndex);
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, v, e.OldStartingIndex);
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, RejectedViewChanged, v, e.OldStartingIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -251,7 +252,7 @@ namespace ObservableCollections
|
||||
}
|
||||
|
||||
list.RemoveRange(e.OldStartingIndex, e.OldItems.Length);
|
||||
this.InvokeOnRemoveRange(ViewChanged, values.Span, views.Span, isMatchAll, matches.Span, e.OldStartingIndex);
|
||||
this.InvokeOnRemoveRange(ViewChanged, RejectedViewChanged, values.Span, views.Span, isMatchAll, matches.Span, e.OldStartingIndex);
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Replace:
|
||||
@ -269,7 +270,7 @@ namespace ObservableCollections
|
||||
list.RemoveAt(e.OldStartingIndex);
|
||||
list.Insert(e.NewStartingIndex, removeItem);
|
||||
|
||||
this.InvokeOnMove(ref filteredCount, ViewChanged, removeItem, e.NewStartingIndex, e.OldStartingIndex);
|
||||
this.InvokeOnMove(ref filteredCount, ViewChanged, RejectedViewChanged, removeItem, e.NewStartingIndex, e.OldStartingIndex);
|
||||
}
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
|
@ -25,6 +25,7 @@ namespace ObservableCollections
|
||||
ISynchronizedViewFilter<T> filter;
|
||||
|
||||
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
|
||||
public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
|
||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||
|
||||
public object SyncRoot { get; }
|
||||
@ -182,7 +183,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (e.NewItem, selector(e.NewItem));
|
||||
queue.Enqueue(v);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, e.NewStartingIndex);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, RejectedViewChanged, v, e.NewStartingIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -191,7 +192,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (item, selector(item));
|
||||
queue.Enqueue(v);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, i++);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, RejectedViewChanged, v, i++);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -200,7 +201,7 @@ namespace ObservableCollections
|
||||
if (e.IsSingleItem)
|
||||
{
|
||||
var v = queue.Dequeue();
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, v.Item1, v.Item2, 0);
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, RejectedViewChanged, v.Item1, v.Item2, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -208,7 +209,7 @@ namespace ObservableCollections
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
var v = queue.Dequeue();
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, v.Item1, v.Item2, 0);
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, RejectedViewChanged, v.Item1, v.Item2, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -31,6 +31,7 @@ namespace ObservableCollections
|
||||
ISynchronizedViewFilter<T> filter;
|
||||
|
||||
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
|
||||
public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
|
||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||
|
||||
public object SyncRoot { get; }
|
||||
@ -196,7 +197,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (e.NewItem, selector(e.NewItem));
|
||||
ringBuffer.AddFirst(v);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, 0);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, RejectedViewChanged, v, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -204,7 +205,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (item, selector(item));
|
||||
ringBuffer.AddFirst(v);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, 0);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, RejectedViewChanged, v, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -215,7 +216,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (e.NewItem, selector(e.NewItem));
|
||||
ringBuffer.AddLast(v);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, ringBuffer.Count - 1);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, RejectedViewChanged, v, ringBuffer.Count - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -223,7 +224,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (item, selector(item));
|
||||
ringBuffer.AddLast(v);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, ringBuffer.Count - 1);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, RejectedViewChanged, v, ringBuffer.Count - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -236,14 +237,14 @@ namespace ObservableCollections
|
||||
if (e.IsSingleItem)
|
||||
{
|
||||
var v = ringBuffer.RemoveFirst();
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, v, 0);
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, RejectedViewChanged, v, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < e.OldItems.Length; i++)
|
||||
{
|
||||
var v = ringBuffer.RemoveFirst();
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, v, 0);
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, RejectedViewChanged, v, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -254,7 +255,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var index = ringBuffer.Count - 1;
|
||||
var v = ringBuffer.RemoveLast();
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, v, index);
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, RejectedViewChanged, v, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -262,7 +263,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var index = ringBuffer.Count - 1;
|
||||
var v = ringBuffer.RemoveLast();
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, v, index);
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, RejectedViewChanged, v, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ namespace ObservableCollections
|
||||
ISynchronizedViewFilter<T> filter;
|
||||
|
||||
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
|
||||
public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
|
||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||
|
||||
public object SyncRoot { get; }
|
||||
@ -187,7 +188,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (e.NewItem, selector(e.NewItem));
|
||||
stack.Push(v);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, 0);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, RejectedViewChanged, v, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -195,7 +196,7 @@ namespace ObservableCollections
|
||||
{
|
||||
var v = (item, selector(item));
|
||||
stack.Push(v);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, 0);
|
||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, RejectedViewChanged, v, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -204,7 +205,7 @@ namespace ObservableCollections
|
||||
if (e.IsSingleItem)
|
||||
{
|
||||
var v = stack.Pop();
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, v.Item1, v.Item2, 0);
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, RejectedViewChanged, v.Item1, v.Item2, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -212,7 +213,7 @@ namespace ObservableCollections
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
var v = stack.Pop();
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, v.Item1, v.Item2, 0);
|
||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, RejectedViewChanged, v.Item1, v.Item2, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -94,108 +94,108 @@ namespace ObservableCollections
|
||||
return filter == SynchronizedViewFilter<T>.Null;
|
||||
}
|
||||
|
||||
internal static void InvokeOnAdd<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, (T value, TView view) value, int index)
|
||||
internal static void InvokeOnAdd<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, Action<RejectedViewChangedAction, int, int>? ev2, (T value, TView view) value, int index)
|
||||
{
|
||||
InvokeOnAdd(collection, ref filteredCount, ev, value.value, value.view, index);
|
||||
InvokeOnAdd(collection, ref filteredCount, ev, ev2, value.value, value.view, index);
|
||||
}
|
||||
|
||||
internal static void InvokeOnAdd<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, T value, TView view, int index)
|
||||
internal static void InvokeOnAdd<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, Action<RejectedViewChangedAction, int, int>? ev2, T value, TView view, int index)
|
||||
{
|
||||
var isMatch = collection.Filter.IsMatch(value);
|
||||
if (isMatch)
|
||||
{
|
||||
filteredCount++;
|
||||
if (ev != null)
|
||||
{
|
||||
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, true, newItem: (value, view), newStartingIndex: index));
|
||||
}
|
||||
ev?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, true, newItem: (value, view), newStartingIndex: index));
|
||||
}
|
||||
}
|
||||
|
||||
internal static void InvokeOnAddRange<T, TView>(this ISynchronizedView<T, TView> collection, NotifyViewChangedEventHandler<T, TView>? ev, ReadOnlySpan<T> values, ReadOnlySpan<TView> views, bool isMatchAll, ReadOnlySpan<bool> matches, int index)
|
||||
{
|
||||
if (ev != null)
|
||||
else
|
||||
{
|
||||
if (isMatchAll)
|
||||
ev2?.Invoke(RejectedViewChangedAction.Add, index, -1);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void InvokeOnAddRange<T, TView>(this ISynchronizedView<T, TView> collection, NotifyViewChangedEventHandler<T, TView>? ev, Action<RejectedViewChangedAction, int, int>? ev2, ReadOnlySpan<T> values, ReadOnlySpan<TView> views, bool isMatchAll, ReadOnlySpan<bool> matches, int index)
|
||||
{
|
||||
if (isMatchAll)
|
||||
{
|
||||
ev?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, isSingleItem: false, newValues: values, newViews: views, newStartingIndex: index));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < matches.Length; i++)
|
||||
{
|
||||
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, isSingleItem: false, newValues: values, newViews: views, newStartingIndex: index));
|
||||
}
|
||||
else
|
||||
{
|
||||
var startingIndex = index;
|
||||
for (var i = 0; i < matches.Length; i++)
|
||||
if (matches[i])
|
||||
{
|
||||
if (matches[i])
|
||||
{
|
||||
var item = (values[i], views[i]);
|
||||
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, isSingleItem: true, newItem: item, newStartingIndex: startingIndex++));
|
||||
}
|
||||
var item = (values[i], views[i]);
|
||||
ev?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, isSingleItem: true, newItem: item, newStartingIndex: index));
|
||||
}
|
||||
else
|
||||
{
|
||||
ev2?.Invoke(RejectedViewChangedAction.Add, index, -1);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void InvokeOnRemove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, (T value, TView view) value, int oldIndex)
|
||||
internal static void InvokeOnRemove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, Action<RejectedViewChangedAction, int, int>? ev2, (T value, TView view) value, int oldIndex)
|
||||
{
|
||||
InvokeOnRemove(collection, ref filteredCount, ev, value.value, value.view, oldIndex);
|
||||
InvokeOnRemove(collection, ref filteredCount, ev, ev2, value.value, value.view, oldIndex);
|
||||
}
|
||||
|
||||
internal static void InvokeOnRemove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, T value, TView view, int oldIndex)
|
||||
internal static void InvokeOnRemove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, Action<RejectedViewChangedAction, int, int>? ev2, T value, TView view, int oldIndex)
|
||||
{
|
||||
var isMatch = collection.Filter.IsMatch(value);
|
||||
if (isMatch)
|
||||
{
|
||||
filteredCount--;
|
||||
if (ev != null)
|
||||
{
|
||||
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, true, oldItem: (value, view), oldStartingIndex: oldIndex));
|
||||
}
|
||||
ev?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, true, oldItem: (value, view), oldStartingIndex: oldIndex));
|
||||
}
|
||||
else
|
||||
{
|
||||
ev2?.Invoke(RejectedViewChangedAction.Remove, oldIndex, -1);
|
||||
}
|
||||
}
|
||||
|
||||
// only use for ObservableList
|
||||
internal static void InvokeOnRemoveRange<T, TView>(this ISynchronizedView<T, TView> collection, NotifyViewChangedEventHandler<T, TView>? ev, ReadOnlySpan<T> values, ReadOnlySpan<TView> views, bool isMatchAll, ReadOnlySpan<bool> matches, int index)
|
||||
internal static void InvokeOnRemoveRange<T, TView>(this ISynchronizedView<T, TView> collection, NotifyViewChangedEventHandler<T, TView>? ev, Action<RejectedViewChangedAction, int, int>? ev2, ReadOnlySpan<T> values, ReadOnlySpan<TView> views, bool isMatchAll, ReadOnlySpan<bool> matches, int index)
|
||||
{
|
||||
if (ev != null)
|
||||
if (isMatchAll)
|
||||
{
|
||||
if (isMatchAll)
|
||||
ev?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, isSingleItem: false, oldValues: values, oldViews: views, oldStartingIndex: index));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < matches.Length; i++)
|
||||
{
|
||||
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, isSingleItem: false, oldValues: values, oldViews: views, oldStartingIndex: index));
|
||||
}
|
||||
else
|
||||
{
|
||||
var startingIndex = index;
|
||||
for (var i = 0; i < matches.Length; i++)
|
||||
if (matches[i])
|
||||
{
|
||||
if (matches[i])
|
||||
{
|
||||
var item = (values[i], views[i]);
|
||||
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, isSingleItem: true, oldItem: item, oldStartingIndex: index)); //remove for list, always same index
|
||||
}
|
||||
else
|
||||
{
|
||||
index++; // not matched, skip index
|
||||
}
|
||||
var item = (values[i], views[i]);
|
||||
ev?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, isSingleItem: true, oldItem: item, oldStartingIndex: index)); //remove for list, always same index
|
||||
}
|
||||
else
|
||||
{
|
||||
ev2?.Invoke(RejectedViewChangedAction.Remove, index, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void InvokeOnMove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, (T value, TView view) value, int index, int oldIndex)
|
||||
internal static void InvokeOnMove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, Action<RejectedViewChangedAction, int, int>? ev2, (T value, TView view) value, int index, int oldIndex)
|
||||
{
|
||||
InvokeOnMove(collection, ref filteredCount, ev, value.value, value.view, index, oldIndex);
|
||||
InvokeOnMove(collection, ref filteredCount, ev, ev2, value.value, value.view, index, oldIndex);
|
||||
}
|
||||
|
||||
internal static void InvokeOnMove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, T value, TView view, int index, int oldIndex)
|
||||
internal static void InvokeOnMove<T, TView>(this ISynchronizedView<T, TView> collection, ref int filteredCount, NotifyViewChangedEventHandler<T, TView>? ev, Action<RejectedViewChangedAction, int, int>? ev2, T value, TView view, int index, int oldIndex)
|
||||
{
|
||||
if (ev != null)
|
||||
// move does not changes filtered-count
|
||||
var isMatch = collection.Filter.IsMatch(value);
|
||||
if (isMatch)
|
||||
{
|
||||
// move does not changes filtered-count
|
||||
var isMatch = collection.Filter.IsMatch(value);
|
||||
if (isMatch)
|
||||
{
|
||||
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Move, true, newItem: (value, view), newStartingIndex: index, oldStartingIndex: oldIndex));
|
||||
}
|
||||
ev?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Move, true, newItem: (value, view), newStartingIndex: index, oldStartingIndex: oldIndex));
|
||||
}
|
||||
else
|
||||
{
|
||||
ev2?.Invoke(RejectedViewChangedAction.Move, index, oldIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,29 +212,19 @@ namespace ObservableCollections
|
||||
|
||||
if (bothMatched)
|
||||
{
|
||||
if (ev != null)
|
||||
{
|
||||
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Replace, true, newItem: (value, view), oldItem: (oldValue, oldView), newStartingIndex: index, oldStartingIndex: oldIndex >= 0 ? oldIndex : index));
|
||||
}
|
||||
ev?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Replace, true, newItem: (value, view), oldItem: (oldValue, oldView), newStartingIndex: index, oldStartingIndex: oldIndex >= 0 ? oldIndex : index));
|
||||
}
|
||||
else if (oldMatched)
|
||||
{
|
||||
// only-old is remove
|
||||
filteredCount--;
|
||||
if (ev != null)
|
||||
{
|
||||
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, true, oldItem: (value, view), oldStartingIndex: oldIndex));
|
||||
}
|
||||
|
||||
ev?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Remove, true, oldItem: (value, view), oldStartingIndex: oldIndex));
|
||||
}
|
||||
else if (newMatched)
|
||||
{
|
||||
// only-new is add
|
||||
filteredCount++;
|
||||
if (ev != null)
|
||||
{
|
||||
ev.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, true, newItem: (value, view), newStartingIndex: index));
|
||||
}
|
||||
ev?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Add, true, newItem: (value, view), newStartingIndex: index));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ internal class FiltableSynchronizedViewList<T, TView> : ISynchronizedViewList<TV
|
||||
{
|
||||
listView = new AlternateIndexList<TView>(IterateFilteredIndexedViewsOfParent());
|
||||
parent.ViewChanged += Parent_ViewChanged;
|
||||
parent.RejectedViewChanged += Parent_RejectedViewChanged;
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,6 +154,27 @@ internal class FiltableSynchronizedViewList<T, TView> : ISynchronizedViewList<TV
|
||||
}
|
||||
}
|
||||
|
||||
private void Parent_RejectedViewChanged(RejectedViewChangedAction arg1, int index, int oldIndex)
|
||||
{
|
||||
lock (gate)
|
||||
{
|
||||
switch (arg1)
|
||||
{
|
||||
case RejectedViewChangedAction.Add:
|
||||
listView.UpdateAlternateIndex(index, 1);
|
||||
break;
|
||||
case RejectedViewChangedAction.Remove:
|
||||
listView.UpdateAlternateIndex(index, -1);
|
||||
break;
|
||||
case RejectedViewChangedAction.Move:
|
||||
listView.TryReplaceAlternateIndex(oldIndex, index);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnCollectionChanged(in SynchronizedViewChangedEventArgs<T, TView> args)
|
||||
{
|
||||
}
|
||||
@ -198,6 +220,7 @@ internal class FiltableSynchronizedViewList<T, TView> : ISynchronizedViewList<TV
|
||||
public void Dispose()
|
||||
{
|
||||
parent.ViewChanged -= Parent_ViewChanged;
|
||||
parent.RejectedViewChanged -= Parent_RejectedViewChanged;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user