add Insert, Remove, RemoveAt, Clear, other

This commit is contained in:
zerodev1200 2024-10-17 23:26:52 +09:00
parent 367be8717c
commit 62b959c2c2
4 changed files with 278 additions and 39 deletions

View File

@ -57,6 +57,10 @@ namespace ObservableCollections
void SetViewAt(int index, TView view); void SetViewAt(int index, TView view);
void SetToSourceCollection(int index, T value); void SetToSourceCollection(int index, T value);
void AddToSourceCollection(T value); void AddToSourceCollection(T value);
void InsertIntoSourceCollection(int index, T value);
bool RemoveFromSourceCollection(T value);
void RemoveAtSourceCollection(int index);
void ClearSourceCollection();
IWritableSynchronizedViewList<TView> ToWritableViewList(WritableViewChangedEventHandler<T, TView> converter); IWritableSynchronizedViewList<TView> ToWritableViewList(WritableViewChangedEventHandler<T, TView> converter);
NotifyCollectionChangedSynchronizedViewList<TView> ToWritableNotifyCollectionChanged(); NotifyCollectionChangedSynchronizedViewList<TView> ToWritableNotifyCollectionChanged();
NotifyCollectionChangedSynchronizedViewList<TView> ToWritableNotifyCollectionChanged(WritableViewChangedEventHandler<T, TView> converter); NotifyCollectionChangedSynchronizedViewList<TView> ToWritableNotifyCollectionChanged(WritableViewChangedEventHandler<T, TView> converter);
@ -100,8 +104,8 @@ namespace ObservableCollections
} }
public abstract int Count { get; } public abstract int Count { get; }
public bool IsReadOnly => false; public virtual bool IsReadOnly { get; } = true;
public bool IsFixedSize => false; public bool IsFixedSize => IsReadOnly;
public bool IsSynchronized => true; public bool IsSynchronized => true;
public object SyncRoot => gate; public object SyncRoot => gate;
@ -113,9 +117,14 @@ namespace ObservableCollections
int IList.Add(object? value) int IList.Add(object? value)
{ {
Add((TView)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); public abstract bool Contains(TView item);
bool IList.Contains(object? value) bool IList.Contains(object? value)
@ -150,17 +159,43 @@ namespace ObservableCollections
return value is TView || value == null && default(TView) == null; return value is TView || value == null && default(TView) == null;
} }
void ICollection<TView>.Clear() => throw new NotSupportedException(); void ICollection<TView>.Clear()
void IList.Clear() => throw new NotSupportedException(); {
Clear();
}
void IList.Clear()
{
Clear();
}
void ICollection<TView>.CopyTo(TView[] array, int arrayIndex) => throw new NotSupportedException(); void ICollection<TView>.CopyTo(TView[] array, int arrayIndex) => throw new NotSupportedException();
void ICollection.CopyTo(Array array, int index) => throw new NotSupportedException(); void ICollection.CopyTo(Array array, int index) => throw new NotSupportedException();
void IList<TView>.Insert(int index, TView item) => throw new NotSupportedException(); void IList<TView>.Insert(int index, TView item)
void IList.Insert(int index, object? value) => throw new NotSupportedException(); {
bool ICollection<TView>.Remove(TView item) => throw new NotSupportedException(); Insert(index, item);
void IList.Remove(object? value) => throw new NotSupportedException(); }
void IList.RemoveAt(int index) => throw new NotSupportedException();
void IList.Insert(int index, object? value)
{
Insert(index, (TView)value!);
}
bool ICollection<TView>.Remove(TView item)
{
return Remove(item!);
}
void IList.Remove(object? value)
{
Remove((TView)value!);
}
void IList.RemoveAt(int index)
{
RemoveAt(index);
}
void IList<TView>.RemoveAt(int index) => throw new NotSupportedException(); void IList<TView>.RemoveAt(int index) => throw new NotSupportedException();
} }
@ -198,4 +233,4 @@ namespace ObservableCollections
return new NonFilteredSynchronizedViewList<T, TView>(collection.CreateView(transform), isSupportRangeFeature: false, collectionEventDispatcher, null); return new NonFilteredSynchronizedViewList<T, TView>(collection.CreateView(transform), isSupportRangeFeature: false, collectionEventDispatcher, null);
} }
} }
} }

View File

@ -189,6 +189,25 @@ internal sealed class ObservableListSynchronizedViewList<T> : NotifyCollectionCh
{ {
parent.Add(item); 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) public override bool Contains(T item)
{ {
@ -199,4 +218,4 @@ internal sealed class ObservableListSynchronizedViewList<T> : NotifyCollectionCh
{ {
return parent.IndexOf(item); return parent.IndexOf(item);
} }
} }

View File

@ -367,6 +367,37 @@ namespace ObservableCollections
source.Add(value); 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<TView> ToWritableViewList(WritableViewChangedEventHandler<T, TView> converter) public IWritableSynchronizedViewList<TView> ToWritableViewList(WritableViewChangedEventHandler<T, TView> converter)
{ {
@ -378,10 +409,10 @@ namespace ObservableCollections
return new FiltableSynchronizedViewList<T, TView>(this, return new FiltableSynchronizedViewList<T, TView>(this,
isSupportRangeFeature: false, isSupportRangeFeature: false,
converter: static (TView newView, T originalValue, ref bool setValue) => converter: static (TView newView, T originalValue, ref bool setValue) =>
{ {
setValue = true; setValue = true;
return originalValue; return originalValue;
}); });
} }
public NotifyCollectionChangedSynchronizedViewList<TView> ToWritableNotifyCollectionChanged(WritableViewChangedEventHandler<T, TView> converter) public NotifyCollectionChangedSynchronizedViewList<TView> ToWritableNotifyCollectionChanged(WritableViewChangedEventHandler<T, TView> converter)
@ -393,12 +424,12 @@ namespace ObservableCollections
{ {
return new FiltableSynchronizedViewList<T, TView>(this, return new FiltableSynchronizedViewList<T, TView>(this,
isSupportRangeFeature: false, isSupportRangeFeature: false,
collectionEventDispatcher, eventDispatcher: collectionEventDispatcher,
static (TView newView, T originalValue, ref bool setValue) => converter: static (TView newView, T originalValue, ref bool setValue) =>
{ {
setValue = true; setValue = true;
return originalValue; return originalValue;
}); });
} }
public NotifyCollectionChangedSynchronizedViewList<TView> ToWritableNotifyCollectionChanged(WritableViewChangedEventHandler<T, TView> converter, ICollectionEventDispatcher? collectionEventDispatcher) public NotifyCollectionChangedSynchronizedViewList<TView> ToWritableNotifyCollectionChanged(WritableViewChangedEventHandler<T, TView> converter, ICollectionEventDispatcher? collectionEventDispatcher)

View File

@ -337,21 +337,22 @@ internal sealed class FiltableSynchronizedViewList<T, TView> : NotifyCollectionC
} }
set set
{ {
if (converter == null || parent is not IWritableSynchronizedView<T, TView> writableView) if (IsReadOnly)
{ {
throw new NotSupportedException("This CollectionView does not support set. If base type is ObservableList<T>, you can use ToWritableSynchronizedView and ToWritableNotifyCollectionChanged."); throw new NotSupportedException("This CollectionView does not support Set. If base type is ObservableList<T>, you can use CreateWritableView and ToWritableNotifyCollectionChanged.");
} }
else else
{ {
var writableView = parent as IWritableSynchronizedView<T, TView>;
var originalIndex = listView.GetAlternateIndex(index); var originalIndex = listView.GetAlternateIndex(index);
var (originalValue, _) = writableView.GetAt(originalIndex); var (originalValue, _) = writableView!.GetAt(originalIndex);
// update view // update view
writableView.SetViewAt(originalIndex, value); writableView.SetViewAt(originalIndex, value);
listView[index] = value; listView[index] = value;
var setValue = true; var setValue = true;
var newOriginal = converter(value, originalValue, ref setValue); var newOriginal = converter!(value, originalValue, ref setValue);
if (setValue) if (setValue)
{ {
@ -372,6 +373,8 @@ internal sealed class FiltableSynchronizedViewList<T, TView> : NotifyCollectionC
} }
} }
public override bool IsReadOnly => converter == null || parent is not IWritableSynchronizedView<T, TView>;
public override IEnumerator<TView> GetEnumerator() public override IEnumerator<TView> GetEnumerator()
{ {
lock (gate) lock (gate)
@ -385,17 +388,91 @@ internal sealed class FiltableSynchronizedViewList<T, TView> : NotifyCollectionC
public override void Add(TView item) public override void Add(TView item)
{ {
if (converter == null || parent is not IWritableSynchronizedView<T, TView> writableView) if (IsReadOnly)
{ {
throw new NotSupportedException("This CollectionView does not support Add. If base type is ObservableList<T>, you can use ToWritableSynchronizedView and ToWritableNotifyCollectionChanged."); throw new NotSupportedException("This CollectionView does not support Add. If base type is ObservableList<T>, you can use CreateWritableView and ToWritableNotifyCollectionChanged.");
} }
else else
{ {
var writableView = parent as IWritableSynchronizedView<T, TView>;
if (typeof(T) == typeof(TView) && item is T tItem)
{
writableView!.AddToSourceCollection(tItem);
return;
}
var setValue = false; var setValue = false;
var newOriginal = converter(item, default!, ref setValue); var newOriginal = converter!(item, default!, ref setValue);
// always add // 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<T>, you can use CreateWritableView and ToWritableNotifyCollectionChanged.");
}
else
{
var writableView = parent as IWritableSynchronizedView<T, TView>;
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<T>, you can use CreateWritableView and ToWritableNotifyCollectionChanged.");
}
else
{
var writableView = parent as IWritableSynchronizedView<T, TView>;
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<T>, you can use CreateWritableView and ToWritableNotifyCollectionChanged.");
}
else
{
var writableView = parent as IWritableSynchronizedView<T, TView>;
writableView!.RemoveAtSourceCollection(index);
}
}
public override void Clear()
{
if (IsReadOnly)
{
throw new NotSupportedException("This CollectionView does not support Clear. If base type is ObservableList<T>, you can use CreateWritableView and ToWritableNotifyCollectionChanged.");
}
else
{
var writableView = parent as IWritableSynchronizedView<T, TView>;
writableView!.ClearSourceCollection();
} }
} }
@ -762,20 +839,21 @@ internal sealed class NonFilteredSynchronizedViewList<T, TView> : NotifyCollecti
} }
set set
{ {
if (converter == null || parent is not IWritableSynchronizedView<T, TView> writableView) if (IsReadOnly)
{ {
throw new NotSupportedException("This CollectionView does not support set. If base type is ObservableList<T>, you can use ToWritableSynchronizedView and ToWritableNotifyCollectionChanged."); throw new NotSupportedException("This CollectionView does not support set. If base type is ObservableList<T>, you can use ToWritableNotifyCollectionChanged.");
} }
else else
{ {
var (originalValue, _) = writableView.GetAt(index); var writableView = parent as IWritableSynchronizedView<T, TView>;
var (originalValue, _) = writableView!.GetAt(index);
// update view // update view
writableView.SetViewAt(index, value); writableView.SetViewAt(index, value);
listView[index] = value; listView[index] = value;
var setValue = true; var setValue = true;
var newOriginal = converter(value, originalValue, ref setValue); var newOriginal = converter!(value, originalValue, ref setValue);
if (setValue) if (setValue)
{ {
@ -796,6 +874,8 @@ internal sealed class NonFilteredSynchronizedViewList<T, TView> : NotifyCollecti
} }
} }
public override bool IsReadOnly => converter == null || parent is not IWritableSynchronizedView<T, TView>;
public override IEnumerator<TView> GetEnumerator() public override IEnumerator<TView> GetEnumerator()
{ {
lock (gate) lock (gate)
@ -809,17 +889,91 @@ internal sealed class NonFilteredSynchronizedViewList<T, TView> : NotifyCollecti
public override void Add(TView item) public override void Add(TView item)
{ {
if (converter == null || parent is not IWritableSynchronizedView<T, TView> writableView) if (IsReadOnly)
{ {
throw new NotSupportedException("This CollectionView does not support Add. If base type is ObservableList<T>, you can use ToWritableSynchronizedView and ToWritableNotifyCollectionChanged."); throw new NotSupportedException("This CollectionView does not support Add. If base type is ObservableList<T>, you can use ToWritableNotifyCollectionChanged.");
} }
else else
{ {
var writableView = parent as IWritableSynchronizedView<T, TView>;
if (typeof(T) == typeof(TView) && item is T tItem)
{
writableView!.AddToSourceCollection(tItem);
return;
}
var setValue = false; var setValue = false;
var newOriginal = converter(item, default!, ref setValue); var newOriginal = converter!(item, default!, ref setValue);
// always add // 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<T>, you can use ToWritableNotifyCollectionChanged.");
}
else
{
var writableView = parent as IWritableSynchronizedView<T, TView>;
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<T>, you can use ToWritableNotifyCollectionChanged.");
}
else
{
var writableView = parent as IWritableSynchronizedView<T, TView>;
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<T>, you can use ToWritableNotifyCollectionChanged.");
}
else
{
var writableView = parent as IWritableSynchronizedView<T, TView>;
writableView!.RemoveAtSourceCollection(index);
}
}
public override void Clear()
{
if (IsReadOnly)
{
throw new NotSupportedException("This CollectionView does not support Clear. If base type is ObservableList<T>, you can use ToWritableNotifyCollectionChanged.");
}
else
{
var writableView = parent as IWritableSynchronizedView<T, TView>;
writableView!.ClearSourceCollection();
} }
} }
@ -860,4 +1014,4 @@ internal sealed class NonFilteredSynchronizedViewList<T, TView> : NotifyCollecti
parent.ViewChanged -= Parent_ViewChanged; parent.ViewChanged -= Parent_ViewChanged;
parent.Dispose(); // Dispose parent parent.Dispose(); // Dispose parent
} }
} }