lll
This commit is contained in:
parent
68618fda10
commit
9ffd0417ba
@ -13,7 +13,7 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
event NotifyCollectionChangedEventHandler<T>? CollectionChanged;
|
event NotifyCollectionChangedEventHandler<T>? CollectionChanged;
|
||||||
object SyncRoot { get; }
|
object SyncRoot { get; }
|
||||||
ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false);
|
ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IReadOnlyObservableList<T> :
|
public interface IReadOnlyObservableList<T> :
|
||||||
@ -36,7 +36,9 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
object SyncRoot { get; }
|
object SyncRoot { get; }
|
||||||
ISynchronizedViewFilter<T> Filter { get; }
|
ISynchronizedViewFilter<T> Filter { get; }
|
||||||
|
IEnumerable<(T Value, TView View)> Filtered { get; }
|
||||||
IEnumerable<(T Value, TView View)> Unfiltered { get; }
|
IEnumerable<(T Value, TView View)> Unfiltered { get; }
|
||||||
|
int UnfilteredCount { get; }
|
||||||
|
|
||||||
event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
|
event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
|
||||||
event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||||
|
@ -15,9 +15,11 @@ 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
|
lock (parent.SyncRoot)
|
||||||
// TODO:add
|
{
|
||||||
parent.ViewChanged += Parent_ViewChanged;
|
this.listView = parent.ToList();
|
||||||
|
parent.ViewChanged += Parent_ViewChanged;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Parent_ViewChanged(SynchronizedViewChangedEventArgs<T, TView> e)
|
private void Parent_ViewChanged(SynchronizedViewChangedEventArgs<T, TView> e)
|
||||||
|
@ -9,9 +9,9 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
public sealed partial class ObservableList<T> : IList<T>, IReadOnlyObservableList<T>
|
public sealed partial class ObservableList<T> : IList<T>, IReadOnlyObservableList<T>
|
||||||
{
|
{
|
||||||
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false)
|
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform)
|
||||||
{
|
{
|
||||||
return new View<TView>(this, transform, reverse);
|
return new View<TView>(this, transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class View<TView> : ISynchronizedView<T, TView>
|
internal sealed class View<TView> : ISynchronizedView<T, TView>
|
||||||
@ -26,7 +26,6 @@ namespace ObservableCollections
|
|||||||
|
|
||||||
readonly ObservableList<T> source;
|
readonly ObservableList<T> source;
|
||||||
readonly Func<T, TView> selector;
|
readonly Func<T, TView> selector;
|
||||||
readonly bool reverse;
|
|
||||||
readonly List<(T, TView)> list;
|
readonly List<(T, TView)> list;
|
||||||
int filteredCount;
|
int filteredCount;
|
||||||
|
|
||||||
@ -37,11 +36,10 @@ namespace ObservableCollections
|
|||||||
|
|
||||||
public object SyncRoot { get; }
|
public object SyncRoot { get; }
|
||||||
|
|
||||||
public View(ObservableList<T> source, Func<T, TView> selector, bool reverse)
|
public View(ObservableList<T> source, Func<T, TView> selector)
|
||||||
{
|
{
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.selector = selector;
|
this.selector = selector;
|
||||||
this.reverse = reverse;
|
|
||||||
this.filter = SynchronizedViewFilter<T>.Null;
|
this.filter = SynchronizedViewFilter<T>.Null;
|
||||||
this.SyncRoot = new object();
|
this.SyncRoot = new object();
|
||||||
lock (source.SyncRoot)
|
lock (source.SyncRoot)
|
||||||
@ -63,6 +61,17 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int UnfilteredCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
return list.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T> filter)
|
public void AttachFilter(ISynchronizedViewFilter<T> filter)
|
||||||
{
|
{
|
||||||
if (filter.IsNullFilter())
|
if (filter.IsNullFilter())
|
||||||
@ -114,25 +123,31 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<(T, TView)> GetEnumerator()
|
public IEnumerator<TView> GetEnumerator()
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
if (!reverse)
|
foreach (var item in list)
|
||||||
|
{
|
||||||
|
if (filter.IsMatch(item.Item1))
|
||||||
|
{
|
||||||
|
yield return item.Item2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
|
public IEnumerable<(T Value, TView View)> Filtered
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
foreach (var item in list)
|
foreach (var item in list)
|
||||||
{
|
{
|
||||||
if (filter.IsMatch(item.Item1, item.Item2))
|
if (filter.IsMatch(item.Item1))
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var item in list.AsEnumerable().Reverse())
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Item1, item.Item2))
|
|
||||||
{
|
{
|
||||||
yield return item;
|
yield return item;
|
||||||
}
|
}
|
||||||
@ -141,7 +156,19 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
public IEnumerable<(T Value, TView View)> Unfiltered
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
foreach (var item in list)
|
||||||
|
{
|
||||||
|
yield return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
@ -171,11 +198,7 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
var v = (item, selector(item));
|
var v = (item, selector(item));
|
||||||
list.Add(v);
|
list.Add(v);
|
||||||
if (filter.IsMatch(v))
|
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, i++);
|
||||||
{
|
|
||||||
filteredCount++;
|
|
||||||
}
|
|
||||||
filter.InvokeOnAdd(v, i++);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,20 +209,17 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
var v = (e.NewItem, selector(e.NewItem));
|
var v = (e.NewItem, selector(e.NewItem));
|
||||||
list.Insert(e.NewStartingIndex, v);
|
list.Insert(e.NewStartingIndex, v);
|
||||||
filter.InvokeOnAdd(v, e.NewStartingIndex);
|
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, e.NewStartingIndex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// inefficient copy, need refactoring
|
|
||||||
var newArray = new (T, TView)[e.NewItems.Length];
|
|
||||||
var span = e.NewItems;
|
var span = e.NewItems;
|
||||||
for (var i = 0; i < span.Length; i++)
|
for (var i = 0; i < span.Length; i++)
|
||||||
{
|
{
|
||||||
var v = (span[i], selector(span[i]));
|
var v = (span[i], selector(span[i]));
|
||||||
newArray[i] = v;
|
list.Insert(e.NewStartingIndex + i, v); // should we use InsertRange?
|
||||||
filter.InvokeOnAdd(v, e.NewStartingIndex + i);
|
this.InvokeOnAdd(ref filteredCount, ViewChanged, v, e.NewStartingIndex + i);
|
||||||
}
|
}
|
||||||
list.InsertRange(e.NewStartingIndex, newArray);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -208,7 +228,7 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
var v = list[e.OldStartingIndex];
|
var v = list[e.OldStartingIndex];
|
||||||
list.RemoveAt(e.OldStartingIndex);
|
list.RemoveAt(e.OldStartingIndex);
|
||||||
filter.InvokeOnRemove(v, e.OldStartingIndex);
|
this.InvokeOnRemove(ref filteredCount, ViewChanged, v, e.OldStartingIndex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -216,10 +236,9 @@ namespace ObservableCollections
|
|||||||
for (var i = e.OldStartingIndex; i < len; i++)
|
for (var i = e.OldStartingIndex; i < len; i++)
|
||||||
{
|
{
|
||||||
var v = list[i];
|
var v = list[i];
|
||||||
filter.InvokeOnRemove(v, e.OldStartingIndex + i);
|
list.RemoveAt(e.OldStartingIndex + i); // should we use RemoveRange?
|
||||||
|
this.InvokeOnRemove(ref filteredCount, ViewChanged, v, e.OldStartingIndex + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
list.RemoveRange(e.OldStartingIndex, e.OldItems.Length);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Replace:
|
case NotifyCollectionChangedAction.Replace:
|
||||||
@ -228,7 +247,7 @@ namespace ObservableCollections
|
|||||||
var v = (e.NewItem, selector(e.NewItem));
|
var v = (e.NewItem, selector(e.NewItem));
|
||||||
var ov = (e.OldItem, list[e.OldStartingIndex].Item2);
|
var ov = (e.OldItem, list[e.OldStartingIndex].Item2);
|
||||||
list[e.NewStartingIndex] = v;
|
list[e.NewStartingIndex] = v;
|
||||||
filter.InvokeOnReplace(v, ov, e.NewStartingIndex);
|
this.InvokeOnReplace(ref filteredCount, ViewChanged, v, ov, e.NewStartingIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NotifyCollectionChangedAction.Move:
|
case NotifyCollectionChangedAction.Move:
|
||||||
@ -237,18 +256,17 @@ namespace ObservableCollections
|
|||||||
list.RemoveAt(e.OldStartingIndex);
|
list.RemoveAt(e.OldStartingIndex);
|
||||||
list.Insert(e.NewStartingIndex, removeItem);
|
list.Insert(e.NewStartingIndex, removeItem);
|
||||||
|
|
||||||
filter.InvokeOnMove(removeItem, e.NewStartingIndex, e.OldStartingIndex);
|
this.InvokeOnMove(ref filteredCount, ViewChanged, removeItem, e.NewStartingIndex, e.OldStartingIndex);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Reset:
|
case NotifyCollectionChangedAction.Reset:
|
||||||
list.Clear();
|
list.Clear();
|
||||||
filter.InvokeOnReset();
|
this.InvokeOnReset(ref filteredCount, ViewChanged);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
RoutingCollectionChanged?.Invoke(e);
|
|
||||||
CollectionStateChanged?.Invoke(e.Action);
|
CollectionStateChanged?.Invoke(e.Action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user