ObservableList.View.ToNotifyCollectionChanged collection implements IList(allow binding for Avalonia)

This commit is contained in:
neuecc 2024-08-13 20:30:44 +09:00
parent f2e26e95a3
commit fa6a843a49
3 changed files with 155 additions and 6 deletions

View File

@ -1,5 +1,6 @@
using ObservableCollections.Internal; using ObservableCollections.Internal;
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
@ -15,11 +16,11 @@ namespace ObservableCollections
ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false); ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false);
} }
public interface IReadOnlyObservableDictionary<TKey, TValue> : public interface IReadOnlyObservableDictionary<TKey, TValue> :
IReadOnlyDictionary<TKey, TValue>, IObservableCollection<KeyValuePair<TKey, TValue>> IReadOnlyDictionary<TKey, TValue>, IObservableCollection<KeyValuePair<TKey, TValue>>
{ {
} }
public interface IFreezedCollection<T> public interface IFreezedCollection<T>
{ {
ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false); ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false);

View File

@ -132,4 +132,152 @@ namespace ObservableCollections.Internal
} }
} }
} }
internal class ListNotifyCollectionChangedSynchronizedView<T, TView>
: NotifyCollectionChangedSynchronizedView<T, TView>
, IList<TView>
, IList
{
readonly ObservableList<T>.View<TView> view;
public ListNotifyCollectionChangedSynchronizedView(ObservableList<T>.View<TView> parent, ICollectionEventDispatcher? eventDispatcher)
: base(parent, eventDispatcher)
{
this.view = parent;
}
public TView this[int index]
{
get
{
lock (view.SyncRoot)
{
return view.list[index].Item2;
}
}
set => throw new NotSupportedException();
}
object? IList.this[int index]
{
get
{
return this[index];
}
set => throw new NotSupportedException();
}
static bool IsCompatibleObject(object? value)
{
return (value is T) || (value == null && default(T) == null);
}
public bool IsReadOnly => true;
public bool IsFixedSize => false;
public bool IsSynchronized => true;
public object SyncRoot => view.SyncRoot;
public void Add(TView item)
{
throw new NotSupportedException();
}
public int Add(object? value)
{
throw new NotImplementedException();
}
public void Clear()
{
throw new NotSupportedException();
}
public bool Contains(TView item)
{
lock (view.SyncRoot)
{
foreach (var listItem in view.list)
{
if (EqualityComparer<TView>.Default.Equals(listItem.Item2, item))
{
return true;
}
}
}
return false;
}
public bool Contains(object? value)
{
if (IsCompatibleObject(value))
{
return Contains((TView)value!);
}
return false;
}
public void CopyTo(TView[] array, int arrayIndex)
{
throw new NotSupportedException();
}
public void CopyTo(Array array, int index)
{
throw new NotImplementedException();
}
public int IndexOf(TView item)
{
lock (view.SyncRoot)
{
var index = 0;
foreach (var listItem in view.list)
{
if (EqualityComparer<TView>.Default.Equals(listItem.Item2, item))
{
return index;
}
index++;
}
}
return -1;
}
public int IndexOf(object? item)
{
if (IsCompatibleObject(item))
{
return IndexOf((TView)item!);
}
return -1;
}
public void Insert(int index, TView item)
{
throw new NotSupportedException();
}
public void Insert(int index, object? value)
{
throw new NotImplementedException();
}
public bool Remove(TView item)
{
throw new NotSupportedException();
}
public void Remove(object? value)
{
throw new NotImplementedException();
}
public void RemoveAt(int index)
{
throw new NotSupportedException();
}
}
} }

View File

@ -14,7 +14,7 @@ namespace ObservableCollections
return new View<TView>(this, transform, reverse); return new View<TView>(this, transform, reverse);
} }
sealed class View<TView> : ISynchronizedView<T, TView> internal sealed class View<TView> : ISynchronizedView<T, TView>
{ {
public ISynchronizedViewFilter<T, TView> CurrentFilter public ISynchronizedViewFilter<T, TView> CurrentFilter
{ {
@ -27,7 +27,7 @@ namespace ObservableCollections
readonly ObservableList<T> source; readonly ObservableList<T> source;
readonly Func<T, TView> selector; readonly Func<T, TView> selector;
readonly bool reverse; readonly bool reverse;
readonly List<(T, TView)> list; internal readonly List<(T, TView)> list; // be careful to use
ISynchronizedViewFilter<T, TView> filter; ISynchronizedViewFilter<T, TView> filter;
@ -100,7 +100,7 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
return new NotifyCollectionChangedSynchronizedView<T, TView>(this, null); return new ListNotifyCollectionChangedSynchronizedView<T, TView>(this, null);
} }
} }
@ -108,7 +108,7 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
return new NotifyCollectionChangedSynchronizedView<T, TView>(this, collectionEventDispatcher); return new ListNotifyCollectionChangedSynchronizedView<T, TView>(this, collectionEventDispatcher);
} }
} }