This commit is contained in:
neuecc 2024-08-20 17:00:17 +09:00
parent a7d6e51831
commit d5f52ee6b7
4 changed files with 129 additions and 4 deletions

View File

@ -57,6 +57,10 @@ namespace ObservableCollections
//{ //{
//} //}
public interface ISynchronizedViewList<out TView> : IReadOnlyList<TView>, IDisposable
{
}
public interface INotifyCollectionChangedSynchronizedView<out TView> : IReadOnlyCollection<TView>, INotifyCollectionChanged, INotifyPropertyChanged, IDisposable public interface INotifyCollectionChangedSynchronizedView<out TView> : IReadOnlyCollection<TView>, INotifyCollectionChanged, INotifyPropertyChanged, IDisposable
{ {
} }

View File

@ -73,8 +73,8 @@ namespace ObservableCollections
{ {
return filter == SynchronizedViewFilter<T, TView>.Null; return filter == SynchronizedViewFilter<T, TView>.Null;
} }
internal static void InvokeOnAdd<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, int index) 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); filter.InvokeOnAdd(value.value, value.view, index);
@ -139,5 +139,10 @@ 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);
}
} }
} }

View File

@ -1,11 +1,117 @@
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;
using System.ComponentModel; using System.ComponentModel;
using System.Linq;
namespace ObservableCollections.Internal namespace ObservableCollections.Internal
{ {
internal class SynchronizedViewList<T, TView> : ISynchronizedViewList<TView>
{
readonly ISynchronizedView<T, TView> parent;
readonly List<TView> listView;
readonly Func<T, TView> selector;
public SynchronizedViewList(ISynchronizedView<T, TView> parent, Func<T, TView> selector)
{
this.parent = parent;
this.selector = selector;
parent.RoutingCollectionChanged += Parent_RoutingCollectionChanged; // TODO: -=
}
private void Parent_RoutingCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
{
// call in parent.lock.
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
if (e.IsSingleItem)
{
// parent.CurrentFilter.IsMatch(
var item = selector(e.NewItem);
if (e.NewStartingIndex != -1)
{
listView.Insert(e.NewStartingIndex, selector(e.NewItem));
}
else // dict is -1
{
listView.Add(selector(e.NewItem));
}
}
else
{
if (e.NewStartingIndex != -1)
{
var array = ArrayPool<TView>.Shared.Rent(e.NewItems.Length);
try
{
var i = 0;
foreach (var item in e.NewItems)
{
array[i++] = selector(item);
}
listView.InsertRange(e.NewStartingIndex, array.Take(e.NewItems.Length));
}
finally
{
ArrayPool<TView>.Shared.Return(array, true);
}
}
else
{
foreach (var item in e.NewItems)
{
listView.Add(selector(item));
}
}
}
break;
case NotifyCollectionChangedAction.Remove:
break;
case NotifyCollectionChangedAction.Replace:
break;
case NotifyCollectionChangedAction.Move:
break;
case NotifyCollectionChangedAction.Reset:
break;
default:
break;
}
// throw new NotImplementedException();
}
public TView this[int index] => throw new NotImplementedException();
public int Count => throw new NotImplementedException();
public void Dispose()
{
throw new NotImplementedException();
}
public IEnumerator<TView> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
internal class NotifyCollectionChangedSynchronizedView<T, TView> : internal class NotifyCollectionChangedSynchronizedView<T, TView> :
INotifyCollectionChangedSynchronizedView<TView>, INotifyCollectionChangedSynchronizedView<TView>,
ISynchronizedViewFilter<T, TView> ISynchronizedViewFilter<T, TView>

View File

@ -27,7 +27,8 @@ namespace ObservableCollections
readonly ObservableList<T> source; readonly ObservableList<T> source;
readonly Func<T, TView> selector; readonly Func<T, TView> selector;
readonly bool reverse; readonly bool reverse;
internal readonly List<(T, TView)> list; // be careful to use readonly List<(T, TView)> list;
int filteredCount;
ISynchronizedViewFilter<T, TView> filter; ISynchronizedViewFilter<T, TView> filter;
@ -46,6 +47,7 @@ namespace ObservableCollections
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
this.list = source.list.Select(x => (x, selector(x))).ToList(); this.list = source.list.Select(x => (x, selector(x))).ToList();
this.filteredCount = list.Count;
this.source.CollectionChanged += SourceCollectionChanged; this.source.CollectionChanged += SourceCollectionChanged;
} }
} }
@ -56,7 +58,7 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
return list.Count; return filteredCount;
} }
} }
} }
@ -160,6 +162,10 @@ 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))
{
filteredCount++;
}
filter.InvokeOnAdd(v, e.NewStartingIndex); filter.InvokeOnAdd(v, e.NewStartingIndex);
} }
else else
@ -169,6 +175,10 @@ namespace ObservableCollections
{ {
var v = (item, selector(item)); var v = (item, selector(item));
list.Add(v); list.Add(v);
if (filter.IsMatch(v))
{
filteredCount++;
}
filter.InvokeOnAdd(v, i++); filter.InvokeOnAdd(v, i++);
} }
} }