remove unused new observable collection
This commit is contained in:
@@ -1,227 +0,0 @@
|
|||||||
using System.Collections;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public partial class ObservableSortedSet<T> : IReadOnlyCollection<T>, IObservableCollection<T>
|
|
||||||
{
|
|
||||||
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform)
|
|
||||||
{
|
|
||||||
return new View<TView>(this, transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class View<TView> : ISynchronizedView<T, TView>
|
|
||||||
{
|
|
||||||
public ISynchronizedViewFilter<T, TView> Filter
|
|
||||||
{
|
|
||||||
get { lock (SyncRoot) return filter; }
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly ObservableSortedSet<T> source;
|
|
||||||
readonly Func<T, TView> selector;
|
|
||||||
readonly Dictionary<T, (T, TView)> dict;
|
|
||||||
int filteredCount;
|
|
||||||
|
|
||||||
ISynchronizedViewFilter<T, TView> filter;
|
|
||||||
|
|
||||||
public event NotifyViewChangedEventHandler<T, TView>? ViewChanged;
|
|
||||||
public event Action<RejectedViewChangedAction, int, int>? RejectedViewChanged;
|
|
||||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
|
||||||
|
|
||||||
public object SyncRoot { get; }
|
|
||||||
|
|
||||||
public View(ObservableSortedSet<T> source, Func<T, TView> selector)
|
|
||||||
{
|
|
||||||
this.source = source;
|
|
||||||
this.selector = selector;
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
this.SyncRoot = new object();
|
|
||||||
lock (source.SyncRoot)
|
|
||||||
{
|
|
||||||
this.dict = source._set.ToDictionary(x => x, x => (x, selector(x)));
|
|
||||||
this.filteredCount = dict.Count;
|
|
||||||
this.source.CollectionChanged += SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return filteredCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int UnfilteredCount
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return dict.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
|
||||||
{
|
|
||||||
if (filter.IsNullFilter())
|
|
||||||
{
|
|
||||||
ResetFilter();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = filter;
|
|
||||||
this.filteredCount = 0;
|
|
||||||
foreach (var (_, (value, view)) in dict)
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(value, view))
|
|
||||||
{
|
|
||||||
filteredCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset, true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetFilter()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
this.filteredCount = dict.Count;
|
|
||||||
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyCollectionChangedAction.Reset, true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISynchronizedViewList<TView> ToViewList()
|
|
||||||
{
|
|
||||||
return new FiltableSynchronizedViewList<T, TView>(this, isSupportRangeFeature: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public NotifyCollectionChangedSynchronizedViewList<TView> ToNotifyCollectionChanged()
|
|
||||||
{
|
|
||||||
return new FiltableSynchronizedViewList<T, TView>(this, isSupportRangeFeature: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public NotifyCollectionChangedSynchronizedViewList<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher)
|
|
||||||
{
|
|
||||||
return new FiltableSynchronizedViewList<T, TView>(this, isSupportRangeFeature: false, collectionEventDispatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<TView> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in dict)
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Value))
|
|
||||||
{
|
|
||||||
yield return item.Value.Item2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
public IEnumerable<(T Value, TView View)> Filtered
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in dict)
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Value))
|
|
||||||
{
|
|
||||||
yield return item.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<(T Value, TView View)> Unfiltered
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in dict)
|
|
||||||
{
|
|
||||||
yield return item.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this.source.CollectionChanged -= SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
switch (e.Action)
|
|
||||||
{
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var v = (e.NewItem, selector(e.NewItem));
|
|
||||||
dict.Add(e.NewItem, v);
|
|
||||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, RejectedViewChanged, v, -1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var i = e.NewStartingIndex;
|
|
||||||
foreach (var item in e.NewItems)
|
|
||||||
{
|
|
||||||
var v = (item, selector(item));
|
|
||||||
dict.Add(item, v);
|
|
||||||
this.InvokeOnAdd(ref filteredCount, ViewChanged, RejectedViewChanged, v, i++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
if (dict.Remove(e.OldItem, out var value))
|
|
||||||
{
|
|
||||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, RejectedViewChanged, value, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var item in e.OldItems)
|
|
||||||
{
|
|
||||||
if (dict.Remove(item, out var value))
|
|
||||||
{
|
|
||||||
this.InvokeOnRemove(ref filteredCount, ViewChanged, RejectedViewChanged, value, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
dict.Clear();
|
|
||||||
this.InvokeOnReset(ref filteredCount, ViewChanged);
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Replace:
|
|
||||||
case NotifyCollectionChangedAction.Move:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionStateChanged?.Invoke(e.Action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,318 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
// Courtesy of Copilot Agent
|
|
||||||
// Replace with https://github.com/Cysharp/ObservableCollections/pull/111 if it gets merged
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
// can not implements ISet<T> because set operation can not get added/removed values.
|
|
||||||
public partial class ObservableSortedSet<T> : IReadOnlySet<T>, IReadOnlyCollection<T>, IObservableCollection<T> where T : notnull
|
|
||||||
{
|
|
||||||
private readonly SortedSet<T> _set;
|
|
||||||
public object SyncRoot { get; } = new object();
|
|
||||||
|
|
||||||
public ObservableSortedSet()
|
|
||||||
{
|
|
||||||
_set = new SortedSet<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableSortedSet(IComparer<T>? comparer)
|
|
||||||
{
|
|
||||||
_set = new SortedSet<T>(comparer: comparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableSortedSet(IEnumerable<T> collection)
|
|
||||||
{
|
|
||||||
_set = new SortedSet<T>(collection: collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableSortedSet(IEnumerable<T> collection, IComparer<T>? comparer)
|
|
||||||
{
|
|
||||||
_set = new SortedSet<T>(collection: collection, comparer: comparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T>? CollectionChanged;
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return _set.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReadOnly => false;
|
|
||||||
|
|
||||||
public bool Add(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (_set.Add(item))
|
|
||||||
{
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(item, -1));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRange(IEnumerable<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (!items.TryGetNonEnumeratedCount(out var capacity))
|
|
||||||
{
|
|
||||||
capacity = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var list = new ResizableArray<T>(capacity))
|
|
||||||
{
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
if (_set.Add(item))
|
|
||||||
{
|
|
||||||
list.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(list.Span, -1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRange(T[] items)
|
|
||||||
{
|
|
||||||
AddRange(items.AsSpan());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRange(ReadOnlySpan<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
using (var list = new ResizableArray<T>(items.Length))
|
|
||||||
{
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
if (_set.Add(item))
|
|
||||||
{
|
|
||||||
list.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(list.Span, -1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (_set.Remove(item))
|
|
||||||
{
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(item, -1));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveRange(IEnumerable<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (!items.TryGetNonEnumeratedCount(out var capacity))
|
|
||||||
{
|
|
||||||
capacity = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var list = new ResizableArray<T>(capacity))
|
|
||||||
{
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
if (_set.Remove(item))
|
|
||||||
{
|
|
||||||
list.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(list.Span, -1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveRange(T[] items)
|
|
||||||
{
|
|
||||||
RemoveRange(items.AsSpan());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveRange(ReadOnlySpan<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
using (var list = new ResizableArray<T>(items.Length))
|
|
||||||
{
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
if (_set.Remove(item))
|
|
||||||
{
|
|
||||||
list.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(list.Span, -1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
_set.Clear();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Reset());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !NETSTANDARD2_0 && !NET_STANDARD_2_0 && !NET_4_6
|
|
||||||
|
|
||||||
public bool TryGetValue(T equalValue, [MaybeNullWhen(false)] out T actualValue)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return _set.TryGetValue(equalValue, out actualValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public bool Contains(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return _set.Contains(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsProperSubsetOf(IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return _set.IsProperSubsetOf(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsProperSupersetOf(IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return _set.IsProperSupersetOf(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSubsetOf(IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return _set.IsSubsetOf(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSupersetOf(IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return _set.IsSupersetOf(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Overlaps(IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return _set.Overlaps(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetEquals(IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return _set.SetEquals(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in _set)
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IComparer<T> Comparer
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return _set.Comparer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SortedSet-specific properties
|
|
||||||
public T? Min
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return _set.Count > 0 ? _set.Min : default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T? Max
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return _set.Count > 0 ? _set.Max : default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SortedSet-specific methods
|
|
||||||
public IEnumerable<T> Reverse()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return _set.Reverse().ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<T> GetViewBetween(T lowerValue, T upperValue)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return _set.GetViewBetween(lowerValue, upperValue).ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user