diff --git a/sandbox/WpfApp/MainWindow.xaml b/sandbox/WpfApp/MainWindow.xaml
index e9d7411..fbe633b 100644
--- a/sandbox/WpfApp/MainWindow.xaml
+++ b/sandbox/WpfApp/MainWindow.xaml
@@ -5,29 +5,62 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp"
mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
-
+
+
+
+
+
+
+
+
+
+
+
- -->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sandbox/WpfApp/MainWindow.xaml.cs b/sandbox/WpfApp/MainWindow.xaml.cs
index 8c476e2..519cdd4 100644
--- a/sandbox/WpfApp/MainWindow.xaml.cs
+++ b/sandbox/WpfApp/MainWindow.xaml.cs
@@ -87,6 +87,18 @@ namespace WpfApp
public ReactiveCommand AttachFilterCommand { get; } = new ReactiveCommand();
public ReactiveCommand ResetFilterCommand { get; } = new ReactiveCommand();
+ private ObservableList SourceList { get; } = [];
+ private IWritableSynchronizedView writableFilter;
+ private ISynchronizedView notWritableFilter;
+ public NotifyCollectionChangedSynchronizedViewList NotWritableNonFilterView { get; }
+ public NotifyCollectionChangedSynchronizedViewList NotWritableFilterView { get; }
+ public NotifyCollectionChangedSynchronizedViewList WritableNonFilterPersonView { get; }
+ public NotifyCollectionChangedSynchronizedViewList WritableFilterPersonView { get; }
+ public ReactiveCommand AttachFilterCommand2 { get; } = new ReactiveCommand();
+ public ReactiveCommand ResetFilterCommand2 { get; } = new ReactiveCommand();
+ public ReactiveCommand AttachFilterCommand3 { get; } = new ReactiveCommand();
+ public ReactiveCommand ResetFilterCommand3 { get; } = new ReactiveCommand();
+
public ViewModel()
{
observableList.Add(1);
@@ -156,8 +168,97 @@ namespace WpfApp
{
view.ResetFilter();
});
+
+ SourceList.Add(new() { Name = "a", Age = 1 });
+ SourceList.Add(new() { Name = "b", Age = 2 });
+ SourceList.Add(new() { Name = "c", Age = 3 });
+ SourceList.Add(new() { Name = "d", Age = 4 });
+ //NotWritable, NonFilter
+ NotWritableNonFilterView = SourceList.ToNotifyCollectionChanged();
+
+ //NotWritable, Filter
+ notWritableFilter = SourceList.CreateView(x => x);
+ NotWritableFilterView = notWritableFilter.ToNotifyCollectionChanged();
+
+ //Writable, NonFilter
+ WritableNonFilterPersonView = SourceList.ToWritableNotifyCollectionChanged();
+
+ //WritableNonFilterPersonView = SourceList.ToWritableNotifyCollectionChanged(x => x, (Person newView, Person original, ref bool setValue) =>
+ //{
+ // if (setValue)
+ // {
+ // // default setValue == true is Set operation
+ // original.Name = newView.Name;
+ // original.Age = newView.Age;
+
+ // // You can modify setValue to false, it does not set original collection to new value.
+ // // For mutable reference types, when there is only a single,
+ // // bound View and to avoid recreating the View, setting false is effective.
+ // // Otherwise, keeping it true will set the value in the original collection as well,
+ // // and change notifications will be sent to lower-level Views(the delegate for View generation will also be called anew).
+ // setValue = false;
+ // return original;
+ // }
+ // else
+ // {
+ // // default setValue == false is Add operation
+ // return new Person { Age = newView.Age, Name = newView.Name };
+ // }
+ //}, null);
+
+ //Writable, Filter
+ writableFilter = SourceList.CreateWritableView(x => x);
+ WritableFilterPersonView = writableFilter.ToWritableNotifyCollectionChanged();
+
+ //WritableFilterPersonView = writableFilter.ToWritableNotifyCollectionChanged((Person newView, Person original, ref bool setValue) =>
+ //{
+ // if (setValue)
+ // {
+ // // default setValue == true is Set operation
+ // original.Name = newView.Name;
+ // original.Age = newView.Age;
+
+ // // You can modify setValue to false, it does not set original collection to new value.
+ // // For mutable reference types, when there is only a single,
+ // // bound View and to avoid recreating the View, setting false is effective.
+ // // Otherwise, keeping it true will set the value in the original collection as well,
+ // // and change notifications will be sent to lower-level Views(the delegate for View generation will also be called anew).
+ // setValue = false;
+ // return original;
+ // }
+ // else
+ // {
+ // // default setValue == false is Add operation
+ // return new Person { Age = newView.Age, Name = newView.Name };
+ // }
+ //});
+
+ AttachFilterCommand2.Subscribe(_ =>
+ {
+ notWritableFilter.AttachFilter(x => x.Age % 2 == 0);
+ });
+
+ ResetFilterCommand2.Subscribe(_ =>
+ {
+ notWritableFilter.ResetFilter();
+ });
+
+ AttachFilterCommand3.Subscribe(_ =>
+ {
+ writableFilter.AttachFilter(x => x.Age % 2 == 0);
+ });
+
+ ResetFilterCommand3.Subscribe(_ =>
+ {
+ writableFilter.ResetFilter();
+ });
}
}
+ public class Person
+ {
+ public int? Age { get; set; }
+ public string? Name { get; set; }
+ }
public class WpfDispatcherCollection(Dispatcher dispatcher) : ICollectionEventDispatcher
{
diff --git a/src/ObservableCollections/IObservableCollection.cs b/src/ObservableCollections/IObservableCollection.cs
index 9134cbf..8dd232a 100644
--- a/src/ObservableCollections/IObservableCollection.cs
+++ b/src/ObservableCollections/IObservableCollection.cs
@@ -57,7 +57,12 @@ namespace ObservableCollections
void SetViewAt(int index, TView view);
void SetToSourceCollection(int index, T value);
void AddToSourceCollection(T value);
+ void InsertIntoSourceCollection(int index, T value);
+ bool RemoveFromSourceCollection(T value);
+ void RemoveAtSourceCollection(int index);
+ void ClearSourceCollection();
IWritableSynchronizedViewList ToWritableViewList(WritableViewChangedEventHandler converter);
+ NotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged();
NotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged(WritableViewChangedEventHandler converter);
NotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher);
NotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged(WritableViewChangedEventHandler converter, ICollectionEventDispatcher? collectionEventDispatcher);
@@ -99,8 +104,8 @@ namespace ObservableCollections
}
public abstract int Count { get; }
- public bool IsReadOnly => false;
- public bool IsFixedSize => false;
+ public virtual bool IsReadOnly { get; } = true;
+ public bool IsFixedSize => IsReadOnly;
public bool IsSynchronized => true;
public object SyncRoot => gate;
@@ -112,9 +117,14 @@ namespace ObservableCollections
int IList.Add(object? value)
{
Add((TView)value!);
- return -1; // itself does not add in this collection
+ return Count - 1;
}
+ public abstract void Insert(int index, TView item);
+ public abstract bool Remove(TView item);
+ public abstract void RemoveAt(int index);
+ public abstract void Clear();
+
public abstract bool Contains(TView item);
bool IList.Contains(object? value)
@@ -149,17 +159,43 @@ namespace ObservableCollections
return value is TView || value == null && default(TView) == null;
}
- void ICollection.Clear() => throw new NotSupportedException();
- void IList.Clear() => throw new NotSupportedException();
+ void ICollection.Clear()
+ {
+ Clear();
+ }
+ void IList.Clear()
+ {
+ Clear();
+ }
void ICollection.CopyTo(TView[] array, int arrayIndex) => throw new NotSupportedException();
void ICollection.CopyTo(Array array, int index) => throw new NotSupportedException();
- void IList.Insert(int index, TView item) => throw new NotSupportedException();
- void IList.Insert(int index, object? value) => throw new NotSupportedException();
- bool ICollection.Remove(TView item) => throw new NotSupportedException();
- void IList.Remove(object? value) => throw new NotSupportedException();
- void IList.RemoveAt(int index) => throw new NotSupportedException();
+ void IList.Insert(int index, TView item)
+ {
+ Insert(index, item);
+ }
+
+ void IList.Insert(int index, object? value)
+ {
+ Insert(index, (TView)value!);
+ }
+
+ bool ICollection.Remove(TView item)
+ {
+ return Remove(item!);
+ }
+
+ void IList.Remove(object? value)
+ {
+ Remove((TView)value!);
+ }
+
+ void IList.RemoveAt(int index)
+ {
+ RemoveAt(index);
+ }
+
void IList.RemoveAt(int index) => throw new NotSupportedException();
}
@@ -176,25 +212,25 @@ namespace ObservableCollections
return new NonFilteredSynchronizedViewList(collection.CreateView(transform), isSupportRangeFeature: true, null, null);
}
- public static INotifyCollectionChangedSynchronizedViewList ToNotifyCollectionChanged(this IObservableCollection collection)
+ public static NotifyCollectionChangedSynchronizedViewList ToNotifyCollectionChanged(this IObservableCollection collection)
{
return ToNotifyCollectionChanged(collection, null);
}
- public static INotifyCollectionChangedSynchronizedViewList ToNotifyCollectionChanged(this IObservableCollection collection, ICollectionEventDispatcher? collectionEventDispatcher)
+ public static NotifyCollectionChangedSynchronizedViewList ToNotifyCollectionChanged(this IObservableCollection collection, ICollectionEventDispatcher? collectionEventDispatcher)
{
return ToNotifyCollectionChanged(collection, static x => x, collectionEventDispatcher);
}
- public static INotifyCollectionChangedSynchronizedViewList ToNotifyCollectionChanged(this IObservableCollection collection, Func transform)
+ public static NotifyCollectionChangedSynchronizedViewList ToNotifyCollectionChanged(this IObservableCollection collection, Func transform)
{
return ToNotifyCollectionChanged(collection, transform, null!);
}
- public static INotifyCollectionChangedSynchronizedViewList ToNotifyCollectionChanged(this IObservableCollection collection, Func transform, ICollectionEventDispatcher? collectionEventDispatcher)
+ public static NotifyCollectionChangedSynchronizedViewList ToNotifyCollectionChanged(this IObservableCollection collection, Func transform, ICollectionEventDispatcher? collectionEventDispatcher)
{
// Optimized for non filtered
return new NonFilteredSynchronizedViewList(collection.CreateView(transform), isSupportRangeFeature: false, collectionEventDispatcher, null);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ObservableCollections/ObservableList.OptimizeView.cs b/src/ObservableCollections/ObservableList.OptimizeView.cs
index b2a6df6..af48818 100644
--- a/src/ObservableCollections/ObservableList.OptimizeView.cs
+++ b/src/ObservableCollections/ObservableList.OptimizeView.cs
@@ -189,6 +189,25 @@ internal sealed class ObservableListSynchronizedViewList : NotifyCollectionCh
{
parent.Add(item);
}
+ public override void Insert(int index, T item)
+ {
+ parent.Insert(index, item);
+ }
+
+ public override bool Remove(T item)
+ {
+ return parent.Remove(item);
+ }
+
+ public override void RemoveAt(int index)
+ {
+ parent.RemoveAt(index);
+ }
+
+ public override void Clear()
+ {
+ parent.Clear();
+ }
public override bool Contains(T item)
{
@@ -199,4 +218,4 @@ internal sealed class ObservableListSynchronizedViewList : NotifyCollectionCh
{
return parent.IndexOf(item);
}
-}
\ No newline at end of file
+}
diff --git a/src/ObservableCollections/ObservableList.Views.cs b/src/ObservableCollections/ObservableList.Views.cs
index f4e35f2..e3b9498 100644
--- a/src/ObservableCollections/ObservableList.Views.cs
+++ b/src/ObservableCollections/ObservableList.Views.cs
@@ -19,12 +19,12 @@ namespace ObservableCollections
return new View(this, transform);
}
- public INotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged()
+ public NotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged()
{
return ToWritableNotifyCollectionChanged(null);
}
- public INotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher)
+ public NotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher)
{
return ToWritableNotifyCollectionChanged(
static x => x,
@@ -36,12 +36,12 @@ namespace ObservableCollections
collectionEventDispatcher);
}
- public INotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged(Func transform, WritableViewChangedEventHandler? converter)
+ public NotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged(Func transform, WritableViewChangedEventHandler? converter)
{
return ToWritableNotifyCollectionChanged(transform, converter, null!);
}
- public INotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged(Func transform, WritableViewChangedEventHandler? converter, ICollectionEventDispatcher? collectionEventDispatcher)
+ public NotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged(Func transform, WritableViewChangedEventHandler? converter, ICollectionEventDispatcher? collectionEventDispatcher)
{
return new NonFilteredSynchronizedViewList(CreateView(transform), isSupportRangeFeature: false, collectionEventDispatcher, converter);
}
@@ -367,12 +367,54 @@ namespace ObservableCollections
source.Add(value);
}
}
+ public void InsertIntoSourceCollection(int index, T value)
+ {
+ lock (SyncRoot)
+ {
+ source.Insert(index, value);
+ }
+ }
+
+ public bool RemoveFromSourceCollection(T value)
+ {
+ lock (SyncRoot)
+ {
+ return source.Remove(value);
+ }
+ }
+
+ public void RemoveAtSourceCollection(int index)
+ {
+ lock (SyncRoot)
+ {
+ source.RemoveAt(index);
+ }
+ }
+
+ public void ClearSourceCollection()
+ {
+ lock (SyncRoot)
+ {
+ source.Clear();
+ }
+ }
public IWritableSynchronizedViewList ToWritableViewList(WritableViewChangedEventHandler converter)
{
return new FiltableSynchronizedViewList(this, isSupportRangeFeature: true, converter: converter);
}
+ public NotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged()
+ {
+ return new FiltableSynchronizedViewList(this,
+ isSupportRangeFeature: false,
+ converter: static (TView newView, T originalValue, ref bool setValue) =>
+ {
+ setValue = true;
+ return originalValue;
+ });
+ }
+
public NotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged(WritableViewChangedEventHandler converter)
{
return new FiltableSynchronizedViewList(this, isSupportRangeFeature: false, converter: converter);
@@ -382,12 +424,12 @@ namespace ObservableCollections
{
return new FiltableSynchronizedViewList(this,
isSupportRangeFeature: false,
- collectionEventDispatcher,
- static (TView newView, T originalValue, ref bool setValue) =>
- {
- setValue = true;
- return originalValue;
- });
+ eventDispatcher: collectionEventDispatcher,
+ converter: static (TView newView, T originalValue, ref bool setValue) =>
+ {
+ setValue = true;
+ return originalValue;
+ });
}
public NotifyCollectionChangedSynchronizedViewList ToWritableNotifyCollectionChanged(WritableViewChangedEventHandler converter, ICollectionEventDispatcher? collectionEventDispatcher)
diff --git a/src/ObservableCollections/SynchronizedViewList.cs b/src/ObservableCollections/SynchronizedViewList.cs
index e6c6c2d..c936b2c 100644
--- a/src/ObservableCollections/SynchronizedViewList.cs
+++ b/src/ObservableCollections/SynchronizedViewList.cs
@@ -337,21 +337,22 @@ internal sealed class FiltableSynchronizedViewList : NotifyCollectionC
}
set
{
- if (converter == null || parent is not IWritableSynchronizedView writableView)
+ if (IsReadOnly)
{
- throw new NotSupportedException("This CollectionView does not support set. If base type is ObservableList, you can use ToWritableSynchronizedView and ToWritableNotifyCollectionChanged.");
+ throw new NotSupportedException("This CollectionView does not support Set. If base type is ObservableList, you can use CreateWritableView and ToWritableNotifyCollectionChanged.");
}
else
{
+ var writableView = parent as IWritableSynchronizedView;
var originalIndex = listView.GetAlternateIndex(index);
- var (originalValue, _) = writableView.GetAt(originalIndex);
+ var (originalValue, _) = writableView!.GetAt(originalIndex);
// update view
writableView.SetViewAt(originalIndex, value);
listView[index] = value;
var setValue = true;
- var newOriginal = converter(value, originalValue, ref setValue);
+ var newOriginal = converter!(value, originalValue, ref setValue);
if (setValue)
{
@@ -372,6 +373,8 @@ internal sealed class FiltableSynchronizedViewList : NotifyCollectionC
}
}
+ public override bool IsReadOnly => converter == null || parent is not IWritableSynchronizedView;
+
public override IEnumerator GetEnumerator()
{
lock (gate)
@@ -385,17 +388,91 @@ internal sealed class FiltableSynchronizedViewList : NotifyCollectionC
public override void Add(TView item)
{
- if (converter == null || parent is not IWritableSynchronizedView writableView)
+ if (IsReadOnly)
{
- throw new NotSupportedException("This CollectionView does not support Add. If base type is ObservableList, you can use ToWritableSynchronizedView and ToWritableNotifyCollectionChanged.");
+ throw new NotSupportedException("This CollectionView does not support Add. If base type is ObservableList, you can use CreateWritableView and ToWritableNotifyCollectionChanged.");
}
else
{
+ var writableView = parent as IWritableSynchronizedView;
+ if (typeof(T) == typeof(TView) && item is T tItem)
+ {
+ writableView!.AddToSourceCollection(tItem);
+ return;
+ }
var setValue = false;
- var newOriginal = converter(item, default!, ref setValue);
+ var newOriginal = converter!(item, default!, ref setValue);
// always add
- writableView.AddToSourceCollection(newOriginal);
+ writableView!.AddToSourceCollection(newOriginal);
+ }
+ }
+
+ public override void Insert(int index, TView item)
+ {
+ if (IsReadOnly)
+ {
+ throw new NotSupportedException("This CollectionView does not support Insert. If base type is ObservableList, you can use CreateWritableView and ToWritableNotifyCollectionChanged.");
+ }
+ else
+ {
+ var writableView = parent as IWritableSynchronizedView;
+ if (typeof(T) == typeof(TView) && item is T tItem)
+ {
+ writableView!.InsertIntoSourceCollection(index, tItem);
+ return;
+ }
+ var setValue = false;
+ var newOriginal = converter!(item, default!, ref setValue);
+
+ writableView!.InsertIntoSourceCollection(index, newOriginal);
+ }
+ }
+
+ public override bool Remove(TView item)
+ {
+ if (IsReadOnly)
+ {
+ throw new NotSupportedException("This CollectionView does not support Remove. If base type is ObservableList, you can use CreateWritableView and ToWritableNotifyCollectionChanged.");
+ }
+ else
+ {
+ var writableView = parent as IWritableSynchronizedView;
+ if (typeof(T) == typeof(TView) && item is T tItem)
+ {
+ return writableView!.RemoveFromSourceCollection(tItem);
+ }
+ var setValue = false;
+ var newOriginal = converter!(item, default!, ref setValue);
+
+ // always add
+ return writableView!.RemoveFromSourceCollection(newOriginal);
+ }
+ }
+
+ public override void RemoveAt(int index)
+ {
+ if (IsReadOnly)
+ {
+ throw new NotSupportedException("This CollectionView does not support RemoveAt. If base type is ObservableList, you can use CreateWritableView and ToWritableNotifyCollectionChanged.");
+ }
+ else
+ {
+ var writableView = parent as IWritableSynchronizedView;
+ writableView!.RemoveAtSourceCollection(index);
+ }
+ }
+
+ public override void Clear()
+ {
+ if (IsReadOnly)
+ {
+ throw new NotSupportedException("This CollectionView does not support Clear. If base type is ObservableList, you can use CreateWritableView and ToWritableNotifyCollectionChanged.");
+ }
+ else
+ {
+ var writableView = parent as IWritableSynchronizedView;
+ writableView!.ClearSourceCollection();
}
}
@@ -762,20 +839,21 @@ internal sealed class NonFilteredSynchronizedViewList : NotifyCollecti
}
set
{
- if (converter == null || parent is not IWritableSynchronizedView writableView)
+ if (IsReadOnly)
{
- throw new NotSupportedException("This CollectionView does not support set. If base type is ObservableList, you can use ToWritableSynchronizedView and ToWritableNotifyCollectionChanged.");
+ throw new NotSupportedException("This CollectionView does not support set. If base type is ObservableList, you can use ToWritableNotifyCollectionChanged.");
}
else
{
- var (originalValue, _) = writableView.GetAt(index);
+ var writableView = parent as IWritableSynchronizedView;
+ var (originalValue, _) = writableView!.GetAt(index);
// update view
writableView.SetViewAt(index, value);
listView[index] = value;
var setValue = true;
- var newOriginal = converter(value, originalValue, ref setValue);
+ var newOriginal = converter!(value, originalValue, ref setValue);
if (setValue)
{
@@ -796,6 +874,8 @@ internal sealed class NonFilteredSynchronizedViewList : NotifyCollecti
}
}
+ public override bool IsReadOnly => converter == null || parent is not IWritableSynchronizedView;
+
public override IEnumerator GetEnumerator()
{
lock (gate)
@@ -809,17 +889,91 @@ internal sealed class NonFilteredSynchronizedViewList : NotifyCollecti
public override void Add(TView item)
{
- if (converter == null || parent is not IWritableSynchronizedView writableView)
+ if (IsReadOnly)
{
- throw new NotSupportedException("This CollectionView does not support Add. If base type is ObservableList, you can use ToWritableSynchronizedView and ToWritableNotifyCollectionChanged.");
+ throw new NotSupportedException("This CollectionView does not support Add. If base type is ObservableList, you can use ToWritableNotifyCollectionChanged.");
}
else
{
+ var writableView = parent as IWritableSynchronizedView;
+ if (typeof(T) == typeof(TView) && item is T tItem)
+ {
+ writableView!.AddToSourceCollection(tItem);
+ return;
+ }
var setValue = false;
- var newOriginal = converter(item, default!, ref setValue);
+ var newOriginal = converter!(item, default!, ref setValue);
// always add
- writableView.AddToSourceCollection(newOriginal);
+ writableView!.AddToSourceCollection(newOriginal);
+ }
+ }
+
+ public override void Insert(int index, TView item)
+ {
+ if (IsReadOnly)
+ {
+ throw new NotSupportedException("This CollectionView does not support Insert. If base type is ObservableList, you can use ToWritableNotifyCollectionChanged.");
+ }
+ else
+ {
+ var writableView = parent as IWritableSynchronizedView;
+ if (typeof(T) == typeof(TView) && item is T tItem)
+ {
+ writableView!.InsertIntoSourceCollection(index, tItem);
+ return;
+ }
+ var setValue = false;
+ var newOriginal = converter!(item, default!, ref setValue);
+
+ writableView!.InsertIntoSourceCollection(index, newOriginal);
+ }
+ }
+
+ public override bool Remove(TView item)
+ {
+ if (IsReadOnly)
+ {
+ throw new NotSupportedException("This CollectionView does not support Remove. If base type is ObservableList, you can use ToWritableNotifyCollectionChanged.");
+ }
+ else
+ {
+ var writableView = parent as IWritableSynchronizedView;
+ if (typeof(T) == typeof(TView) && item is T tItem)
+ {
+ return writableView!.RemoveFromSourceCollection(tItem);
+ }
+ var setValue = false;
+ var newOriginal = converter!(item, default!, ref setValue);
+
+ // always add
+ return writableView!.RemoveFromSourceCollection(newOriginal);
+ }
+ }
+
+ public override void RemoveAt(int index)
+ {
+ if (IsReadOnly)
+ {
+ throw new NotSupportedException("This CollectionView does not support RemoveAt. If base type is ObservableList, you can use ToWritableNotifyCollectionChanged.");
+ }
+ else
+ {
+ var writableView = parent as IWritableSynchronizedView;
+ writableView!.RemoveAtSourceCollection(index);
+ }
+ }
+
+ public override void Clear()
+ {
+ if (IsReadOnly)
+ {
+ throw new NotSupportedException("This CollectionView does not support Clear. If base type is ObservableList, you can use ToWritableNotifyCollectionChanged.");
+ }
+ else
+ {
+ var writableView = parent as IWritableSynchronizedView;
+ writableView!.ClearSourceCollection();
}
}
@@ -860,4 +1014,4 @@ internal sealed class NonFilteredSynchronizedViewList : NotifyCollecti
parent.ViewChanged -= Parent_ViewChanged;
parent.Dispose(); // Dispose parent
}
-}
\ No newline at end of file
+}