WritableNotifyCollectionChanged supports Add
This commit is contained in:
parent
dcfb3edd5a
commit
8afb3fb100
57
README.md
57
README.md
@ -374,14 +374,59 @@ public interface IWritableSynchronizedView<T, TView> : ISynchronizedView<T, TVie
|
||||
`ToWritableNotifyCollectionChanged` accepts a delegate called `WritableViewChangedEventHandler`. `newView` receives the newly bound value. If `setValue` is true, it sets a new value to the original collection, triggering notification propagation. The View is also regenerated. If `T originalValue` is a reference type, you can prevent such propagation by setting `setValue` to `false`.
|
||||
|
||||
```csharp
|
||||
var list = new ObservableList<int>();
|
||||
var view = list.CreateWritableView(x => x.ToString());
|
||||
view.AttachFilter(x => x % 2 == 0);
|
||||
IList<string> notify = view.ToWritableNotifyCollectionChanged((string newView, int originalValue, ref bool setValue) =>
|
||||
var list = new ObservableList<Person>()
|
||||
{
|
||||
setValue = true; // or false
|
||||
return int.Parse(newView);
|
||||
new (){ Age = 10, Name = "John" },
|
||||
new (){ Age = 22, Name = "Jeyne" },
|
||||
new (){ Age = 30, Name = "Mike" },
|
||||
};
|
||||
var view = list.CreateWritableView(x => x.Name);
|
||||
view.AttachFilter(x => x.Age >= 20);
|
||||
|
||||
IList<string?> bindable = view.ToWritableNotifyCollectionChanged((string? newView, Person original, ref bool setValue) =>
|
||||
{
|
||||
if (setValue)
|
||||
{
|
||||
// default setValue == true is Set operation
|
||||
original.Name = newView;
|
||||
|
||||
// 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 = null, Name = newView };
|
||||
}
|
||||
});
|
||||
|
||||
bindable[1] = "Bob"; // change Mike(filtered view's [1]) to Bob.
|
||||
bindable.Add("Ken");
|
||||
|
||||
// Show Views
|
||||
foreach (var item in view)
|
||||
{
|
||||
Console.WriteLine(item);
|
||||
}
|
||||
|
||||
Console.WriteLine("---");
|
||||
|
||||
// Show Originals
|
||||
foreach (var item in list)
|
||||
{
|
||||
Console.WriteLine((item.Age, item.Name));
|
||||
}
|
||||
|
||||
public class Person
|
||||
{
|
||||
public int? Age { get; set; }
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
Unity
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>10.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
|
@ -6,30 +6,59 @@ using ObservableCollections;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks.Sources;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
var l = new ObservableList<int>();
|
||||
var view = l.CreateWritableView(x => x.ToString());
|
||||
view.AttachFilter(x => x % 2 == 0);
|
||||
IList<string> notify = view.ToWritableNotifyCollectionChanged((string newView, int originalValue, ref bool setValue) =>
|
||||
var list = new ObservableList<Person>()
|
||||
{
|
||||
new (){ Age = 10, Name = "John" },
|
||||
new (){ Age = 22, Name = "Jeyne" },
|
||||
new (){ Age = 30, Name = "Mike" },
|
||||
};
|
||||
var view = list.CreateWritableView(x => x.Name);
|
||||
view.AttachFilter(x => x.Age >= 20);
|
||||
|
||||
IList<string?> bindable = view.ToWritableNotifyCollectionChanged((string? newView, Person original, ref bool setValue) =>
|
||||
{
|
||||
if (setValue)
|
||||
{
|
||||
// default setValue == true is Set operation
|
||||
original.Name = newView;
|
||||
|
||||
// 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 int.Parse(newView);
|
||||
return original;
|
||||
}
|
||||
else
|
||||
{
|
||||
// default setValue == false is Add operation
|
||||
return new Person { Age = null, Name = newView };
|
||||
}
|
||||
});
|
||||
|
||||
l.Add(0);
|
||||
l.Add(1);
|
||||
l.Add(2);
|
||||
l.Add(3);
|
||||
l.Add(4);
|
||||
l.Add(5);
|
||||
|
||||
notify[1] = "99999";
|
||||
// bindable[0] = "takoyaki";
|
||||
|
||||
foreach (var item in view)
|
||||
{
|
||||
Console.WriteLine(item);
|
||||
}
|
||||
|
||||
Console.WriteLine("---");
|
||||
|
||||
foreach (var item in list)
|
||||
{
|
||||
Console.WriteLine((item.Age, item.Name));
|
||||
}
|
||||
|
||||
public class Person
|
||||
{
|
||||
public int? Age { get; set; }
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
|
||||
|
||||
//var buffer = new ObservableFixedSizeRingBuffer<int>(5);
|
||||
|
||||
|
@ -56,6 +56,7 @@ namespace ObservableCollections
|
||||
(T Value, TView View) GetAt(int index);
|
||||
void SetViewAt(int index, TView view);
|
||||
void SetToSourceCollection(int index, T value);
|
||||
void AddToSourceCollection(T value);
|
||||
IWritableSynchronizedViewList<TView> ToWritableViewList(WritableViewChangedEventHandler<T, TView> converter);
|
||||
INotifyCollectionChangedSynchronizedViewList<TView> ToWritableNotifyCollectionChanged(WritableViewChangedEventHandler<T, TView> converter);
|
||||
INotifyCollectionChangedSynchronizedViewList<TView> ToWritableNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher);
|
||||
|
@ -360,6 +360,14 @@ namespace ObservableCollections
|
||||
}
|
||||
}
|
||||
|
||||
public void AddToSourceCollection(T value)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
source.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
public IWritableSynchronizedViewList<TView> ToWritableViewList(WritableViewChangedEventHandler<T, TView> converter)
|
||||
{
|
||||
return new FiltableWritableSynchronizedViewList<T, TView>(this, converter);
|
||||
|
@ -557,7 +557,7 @@ internal class FiltableWritableSynchronizedViewList<T, TView> : FiltableSynchron
|
||||
|
||||
if (setValue)
|
||||
{
|
||||
writableView.SetToSourceCollection(index, newOriginal);
|
||||
writableView.SetToSourceCollection(originalIndex, newOriginal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -713,7 +713,7 @@ internal class NotifyCollectionChangedSynchronizedViewList<T, TView> :
|
||||
|
||||
if (setValue)
|
||||
{
|
||||
writableView.SetToSourceCollection(index, newOriginal);
|
||||
writableView.SetToSourceCollection(originalIndex, newOriginal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -743,12 +743,24 @@ internal class NotifyCollectionChangedSynchronizedViewList<T, TView> :
|
||||
|
||||
public void Add(TView item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
if (converter == null || parent is not IWritableSynchronizedView<T, TView> writableView)
|
||||
{
|
||||
throw new NotSupportedException("This CollectionView does not support Add. If base type is ObservableList<T>, you can use ToWritableSynchronizedView and ToWritableNotifyCollectionChanged.");
|
||||
}
|
||||
else
|
||||
{
|
||||
var setValue = false;
|
||||
var newOriginal = converter(item, default!, ref setValue);
|
||||
|
||||
// always add
|
||||
writableView.AddToSourceCollection(newOriginal);
|
||||
}
|
||||
}
|
||||
|
||||
public int Add(object? value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Add((TView)value!);
|
||||
return -1; // itself does not add in this collection
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
@ -1020,12 +1032,24 @@ internal class NonFilteredNotifyCollectionChangedSynchronizedViewList<T, TView>
|
||||
|
||||
public void Add(TView item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
if (converter == null || parent is not IWritableSynchronizedView<T, TView> writableView)
|
||||
{
|
||||
throw new NotSupportedException("This CollectionView does not support Add. If base type is ObservableList<T>, you can use ToWritableSynchronizedView and ToWritableNotifyCollectionChanged.");
|
||||
}
|
||||
else
|
||||
{
|
||||
var setValue = false;
|
||||
var newOriginal = converter(item, default!, ref setValue);
|
||||
|
||||
// always add
|
||||
writableView.AddToSourceCollection(newOriginal);
|
||||
}
|
||||
}
|
||||
|
||||
public int Add(object? value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Add((TView)value!);
|
||||
return -1; // itself does not add in this collection
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
|
Loading…
x
Reference in New Issue
Block a user