Merge pull request #25 from Cysharp/hadashiA/fix-notify-collection-changed
Change the INotifyCollectionChaneged to IE<TView> from IE<(T, View)>
This commit is contained in:
commit
4023a28e4f
@ -24,13 +24,14 @@ 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; }
|
||||||
|
|
||||||
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, TView> filter, bool invokeAddEventForInitialElements = false);
|
||||||
void ResetFilter(Action<T, TView>? resetAction);
|
void ResetFilter(Action<T, TView>? resetAction);
|
||||||
INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged();
|
INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ISortableSynchronizedView<T, TView> : ISynchronizedView<T, TView>
|
public interface ISortableSynchronizedView<T, TView> : ISynchronizedView<T, TView>
|
||||||
@ -44,7 +45,7 @@ namespace ObservableCollections
|
|||||||
//{
|
//{
|
||||||
//}
|
//}
|
||||||
|
|
||||||
public interface INotifyCollectionChangedSynchronizedView<T, TView> : ISynchronizedView<T, TView>, INotifyCollectionChanged, INotifyPropertyChanged
|
public interface INotifyCollectionChangedSynchronizedView<out TView> : IReadOnlyCollection<TView>, INotifyCollectionChanged, INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,11 @@ namespace ObservableCollections.Internal
|
|||||||
|
|
||||||
ISynchronizedViewFilter<T, TView> filter;
|
ISynchronizedViewFilter<T, TView> filter;
|
||||||
|
|
||||||
|
public ISynchronizedViewFilter<T, TView> CurrentFilter
|
||||||
|
{
|
||||||
|
get { lock (SyncRoot) return filter; }
|
||||||
|
}
|
||||||
|
|
||||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||||
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
||||||
|
|
||||||
@ -107,7 +112,7 @@ namespace ObservableCollections.Internal
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
|
||||||
{
|
{
|
||||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
||||||
}
|
}
|
||||||
@ -119,6 +124,11 @@ namespace ObservableCollections.Internal
|
|||||||
|
|
||||||
ISynchronizedViewFilter<T, TView> filter;
|
ISynchronizedViewFilter<T, TView> filter;
|
||||||
|
|
||||||
|
public ISynchronizedViewFilter<T, TView> CurrentFilter
|
||||||
|
{
|
||||||
|
get { lock (SyncRoot) return filter; }
|
||||||
|
}
|
||||||
|
|
||||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||||
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
||||||
|
|
||||||
@ -206,7 +216,7 @@ namespace ObservableCollections.Internal
|
|||||||
Array.Sort(array, new TViewComparer(viewComparer));
|
Array.Sort(array, new TViewComparer(viewComparer));
|
||||||
}
|
}
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
|
||||||
{
|
{
|
||||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
||||||
}
|
}
|
||||||
|
@ -6,38 +6,22 @@ using System.ComponentModel;
|
|||||||
|
|
||||||
namespace ObservableCollections.Internal
|
namespace ObservableCollections.Internal
|
||||||
{
|
{
|
||||||
internal class NotifyCollectionChangedSynchronizedView<T, TView> : INotifyCollectionChangedSynchronizedView<T, TView>
|
internal class NotifyCollectionChangedSynchronizedView<T, TView> :
|
||||||
|
INotifyCollectionChangedSynchronizedView<TView>,
|
||||||
|
ISynchronizedViewFilter<T, TView>
|
||||||
{
|
{
|
||||||
|
static readonly PropertyChangedEventArgs CountPropertyChangedEventArgs = new("Count");
|
||||||
|
|
||||||
readonly ISynchronizedView<T, TView> parent;
|
readonly ISynchronizedView<T, TView> parent;
|
||||||
static readonly PropertyChangedEventArgs CountPropertyChangedEventArgs = new PropertyChangedEventArgs("Count");
|
readonly ISynchronizedViewFilter<T, TView> currentFilter;
|
||||||
|
|
||||||
public NotifyCollectionChangedSynchronizedView(ISynchronizedView<T, TView> parent)
|
public NotifyCollectionChangedSynchronizedView(ISynchronizedView<T, TView> parent)
|
||||||
{
|
{
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.parent.RoutingCollectionChanged += Parent_RoutingCollectionChanged;
|
currentFilter = parent.CurrentFilter;
|
||||||
|
parent.AttachFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Parent_RoutingCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
|
|
||||||
{
|
|
||||||
CollectionChanged?.Invoke(this, e.ToStandardEventArgs());
|
|
||||||
|
|
||||||
switch (e.Action)
|
|
||||||
{
|
|
||||||
// add, remove, reset will change the count.
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
PropertyChanged?.Invoke(this, CountPropertyChangedEventArgs);
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Replace:
|
|
||||||
case NotifyCollectionChangedAction.Move:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object SyncRoot => parent.SyncRoot;
|
|
||||||
|
|
||||||
public int Count => parent.Count;
|
public int Count => parent.Count;
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler? CollectionChanged;
|
public event NotifyCollectionChangedEventHandler? CollectionChanged;
|
||||||
@ -55,16 +39,43 @@ namespace ObservableCollections.Internal
|
|||||||
remove { parent.RoutingCollectionChanged -= value; }
|
remove { parent.RoutingCollectionChanged -= value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false) => parent.AttachFilter(filter, invokeAddEventForCurrentElements);
|
|
||||||
public void ResetFilter(Action<T, TView>? resetAction) => parent.ResetFilter(resetAction);
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged() => this;
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
this.parent.RoutingCollectionChanged -= Parent_RoutingCollectionChanged;
|
|
||||||
parent.Dispose();
|
parent.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<(T, TView)> GetEnumerator() => parent.GetEnumerator();
|
public IEnumerator<TView> GetEnumerator()
|
||||||
|
{
|
||||||
|
foreach (var (value, view) in parent)
|
||||||
|
{
|
||||||
|
yield return view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => parent.GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => parent.GetEnumerator();
|
||||||
|
|
||||||
|
public bool IsMatch(T value, TView view) => currentFilter.IsMatch(value, view);
|
||||||
|
public void WhenTrue(T value, TView view) => currentFilter.WhenTrue(value, view);
|
||||||
|
public void WhenFalse(T value, TView view) => currentFilter.WhenFalse(value, view);
|
||||||
|
|
||||||
|
public void OnCollectionChanged(ChangedKind changedKind, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs)
|
||||||
|
{
|
||||||
|
currentFilter.OnCollectionChanged(changedKind, value, view, in eventArgs);
|
||||||
|
|
||||||
|
switch (changedKind)
|
||||||
|
{
|
||||||
|
case ChangedKind.Add:
|
||||||
|
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, view, eventArgs.NewStartingIndex));
|
||||||
|
return;
|
||||||
|
case ChangedKind.Remove:
|
||||||
|
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, view, eventArgs.OldStartingIndex));
|
||||||
|
break;
|
||||||
|
case ChangedKind.Move:
|
||||||
|
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, view, eventArgs.NewStartingIndex, eventArgs.OldStartingIndex));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(changedKind), changedKind, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,13 +2,17 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections.Internal
|
namespace ObservableCollections.Internal
|
||||||
{
|
{
|
||||||
internal class SortedView<T, TKey, TView> : ISynchronizedView<T, TView>
|
internal class SortedView<T, TKey, TView> : ISynchronizedView<T, TView>
|
||||||
where TKey : notnull
|
where TKey : notnull
|
||||||
{
|
{
|
||||||
|
public ISynchronizedViewFilter<T, TView> CurrentFilter
|
||||||
|
{
|
||||||
|
get { lock (SyncRoot) return filter; }
|
||||||
|
}
|
||||||
|
|
||||||
readonly IObservableCollection<T> source;
|
readonly IObservableCollection<T> source;
|
||||||
readonly Func<T, TView> transform;
|
readonly Func<T, TView> transform;
|
||||||
readonly Func<T, TKey> identitySelector;
|
readonly Func<T, TKey> identitySelector;
|
||||||
@ -85,7 +89,7 @@ namespace ObservableCollections.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,11 @@ namespace ObservableCollections.Internal
|
|||||||
|
|
||||||
public object SyncRoot { get; } = new object();
|
public object SyncRoot { get; } = new object();
|
||||||
|
|
||||||
|
public ISynchronizedViewFilter<T, TView> CurrentFilter
|
||||||
|
{
|
||||||
|
get { lock (SyncRoot) return filter; }
|
||||||
|
}
|
||||||
|
|
||||||
public SortedViewViewComparer(IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> comparer)
|
public SortedViewViewComparer(IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> comparer)
|
||||||
{
|
{
|
||||||
this.source = source;
|
this.source = source;
|
||||||
@ -89,7 +94,7 @@ namespace ObservableCollections.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard2.0;netstandard2.1;net5.0;net6.0</TargetFrameworks>
|
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net8.0</TargetFrameworks>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>10.0</LangVersion>
|
<LangVersion>12.0</LangVersion>
|
||||||
<ImplicitUsings>disable</ImplicitUsings>
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
|
|
||||||
<!-- NuGet Packaging -->
|
<!-- NuGet Packaging -->
|
||||||
|
@ -39,6 +39,11 @@ namespace ObservableCollections
|
|||||||
public event NotifyCollectionChangedEventHandler<KeyValuePair<TKey, TValue>>? RoutingCollectionChanged;
|
public event NotifyCollectionChangedEventHandler<KeyValuePair<TKey, TValue>>? RoutingCollectionChanged;
|
||||||
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||||
|
|
||||||
|
public ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> CurrentFilter
|
||||||
|
{
|
||||||
|
get { lock (SyncRoot) return filter; }
|
||||||
|
}
|
||||||
|
|
||||||
public int Count
|
public int Count
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -91,7 +96,7 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<KeyValuePair<TKey, TValue>, TView> WithINotifyCollectionChanged()
|
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
|
@ -16,6 +16,11 @@ namespace ObservableCollections
|
|||||||
|
|
||||||
sealed class View<TView> : ISynchronizedView<T, TView>
|
sealed class View<TView> : ISynchronizedView<T, TView>
|
||||||
{
|
{
|
||||||
|
public ISynchronizedViewFilter<T, TView> CurrentFilter
|
||||||
|
{
|
||||||
|
get { lock (SyncRoot) return filter; }
|
||||||
|
}
|
||||||
|
|
||||||
readonly ObservableHashSet<T> source;
|
readonly ObservableHashSet<T> source;
|
||||||
readonly Func<T, TView> selector;
|
readonly Func<T, TView> selector;
|
||||||
readonly Dictionary<T, (T, TView)> dict;
|
readonly Dictionary<T, (T, TView)> dict;
|
||||||
@ -85,7 +90,7 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
|
@ -16,6 +16,14 @@ namespace ObservableCollections
|
|||||||
|
|
||||||
sealed class View<TView> : ISynchronizedView<T, TView>
|
sealed class View<TView> : ISynchronizedView<T, TView>
|
||||||
{
|
{
|
||||||
|
public ISynchronizedViewFilter<T, TView> CurrentFilter
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (SyncRoot) { return filter; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly ObservableList<T> source;
|
readonly ObservableList<T> source;
|
||||||
readonly Func<T, TView> selector;
|
readonly Func<T, TView> selector;
|
||||||
readonly bool reverse;
|
readonly bool reverse;
|
||||||
@ -89,7 +97,7 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
|
@ -62,7 +62,6 @@ namespace ObservableCollections
|
|||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T>? CollectionChanged;
|
public event NotifyCollectionChangedEventHandler<T>? CollectionChanged;
|
||||||
|
|
||||||
|
|
||||||
public void Add(T item)
|
public void Add(T item)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
|
@ -28,6 +28,11 @@ namespace ObservableCollections
|
|||||||
|
|
||||||
public object SyncRoot { get; }
|
public object SyncRoot { get; }
|
||||||
|
|
||||||
|
public ISynchronizedViewFilter<T, TView> CurrentFilter
|
||||||
|
{
|
||||||
|
get { lock (SyncRoot) return filter; }
|
||||||
|
}
|
||||||
|
|
||||||
public View(ObservableQueue<T> source, Func<T, TView> selector, bool reverse)
|
public View(ObservableQueue<T> source, Func<T, TView> selector, bool reverse)
|
||||||
{
|
{
|
||||||
this.source = source;
|
this.source = source;
|
||||||
@ -89,7 +94,7 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,11 @@ namespace ObservableCollections
|
|||||||
// used with ObservableFixedSizeRingBuffer
|
// used with ObservableFixedSizeRingBuffer
|
||||||
internal sealed class View<TView> : ISynchronizedView<T, TView>
|
internal sealed class View<TView> : ISynchronizedView<T, TView>
|
||||||
{
|
{
|
||||||
|
public ISynchronizedViewFilter<T, TView> CurrentFilter
|
||||||
|
{
|
||||||
|
get { lock (SyncRoot) return filter; }
|
||||||
|
}
|
||||||
|
|
||||||
readonly IObservableCollection<T> source;
|
readonly IObservableCollection<T> source;
|
||||||
readonly Func<T, TView> selector;
|
readonly Func<T, TView> selector;
|
||||||
readonly bool reverse;
|
readonly bool reverse;
|
||||||
@ -89,7 +94,7 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,11 @@ namespace ObservableCollections
|
|||||||
|
|
||||||
public object SyncRoot { get; }
|
public object SyncRoot { get; }
|
||||||
|
|
||||||
|
public ISynchronizedViewFilter<T, TView> CurrentFilter
|
||||||
|
{
|
||||||
|
get { lock (SyncRoot) return filter; }
|
||||||
|
}
|
||||||
|
|
||||||
public View(ObservableStack<T> source, Func<T, TView> selector, bool reverse)
|
public View(ObservableStack<T> source, Func<T, TView> selector, bool reverse)
|
||||||
{
|
{
|
||||||
this.source = source;
|
this.source = source;
|
||||||
@ -89,7 +94,7 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
namespace ObservableCollections.Tests;
|
||||||
|
|
||||||
|
public class ToNotifyCollectionChangedTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void ToNotifyCollectionChanged()
|
||||||
|
{
|
||||||
|
var list = new ObservableList<int>();
|
||||||
|
|
||||||
|
list.Add(10);
|
||||||
|
list.Add(20);
|
||||||
|
list.Add(30);
|
||||||
|
|
||||||
|
var notify = list.CreateView(x => $"${x}").ToNotifyCollectionChanged();
|
||||||
|
|
||||||
|
list.Add(40);
|
||||||
|
list.Add(50);
|
||||||
|
|
||||||
|
using var e = notify.GetEnumerator();
|
||||||
|
e.MoveNext().Should().BeTrue();
|
||||||
|
e.Current.Should().Be("$10");
|
||||||
|
e.MoveNext().Should().BeTrue();
|
||||||
|
e.Current.Should().Be("$20");
|
||||||
|
e.MoveNext().Should().BeTrue();
|
||||||
|
e.Current.Should().Be("$30");
|
||||||
|
e.MoveNext().Should().BeTrue();
|
||||||
|
e.Current.Should().Be("$40");
|
||||||
|
e.MoveNext().Should().BeTrue();
|
||||||
|
e.Current.Should().Be("$50");
|
||||||
|
e.MoveNext().Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToNotifyCollectionChanged_Filter()
|
||||||
|
{
|
||||||
|
var list = new ObservableList<int>();
|
||||||
|
|
||||||
|
list.Add(1);
|
||||||
|
list.Add(2);
|
||||||
|
list.Add(5);
|
||||||
|
list.Add(3);
|
||||||
|
|
||||||
|
var view = list.CreateView(x => $"${x}");
|
||||||
|
var notify = view.ToNotifyCollectionChanged();
|
||||||
|
|
||||||
|
view.AttachFilter((value, view) => value % 2 == 0);
|
||||||
|
|
||||||
|
list.Add(4);
|
||||||
|
|
||||||
|
using var e = notify.GetEnumerator();
|
||||||
|
e.MoveNext().Should().BeTrue();
|
||||||
|
e.Current.Should().Be("$2");
|
||||||
|
e.MoveNext().Should().BeTrue();
|
||||||
|
e.Current.Should().Be("$4");
|
||||||
|
e.MoveNext().Should().BeFalse();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user