在下面的代码片段中,似乎 transform(x => x.Bar.Baz)
仅在添加或删除 sl2
中的项目时转发更改,但不转发如果 Baz
的值发生变化。这是预期的行为吗?如何更改它,使所有修改都在 transformed
中找到?
SourceList<FooClass> sl2 = new SourceList<FooClass>();
sl2.Connect()
.Transform(x => x.Bar.Baz)
.Bind(out ReadOnlyObservableCollection<String> transformed)
.Subscribe( x=> { Console.WriteLine("CHANGE from Subscribe"); } );
完整代码如下。运行示例也可在 GitHub 上找到
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using DynamicData;
using DynamicData.Binding;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
namespace ReactivUI_Test
{
class BarClass : ReactiveObject
{
[Reactive] public String Baz { get; set; } = "";
public BarClass(String b) { Baz = b; }
public BarClass() { Baz = "!!!"; }
public override String ToString() { return Baz.ToString(); }
}
class FooClass : ReactiveObject
{
[Reactive] public BarClass Bar { get; set; } = new BarClass();
public override String ToString() { return Bar.ToString(); }
}
class ViewModel: ReactiveObject
{
[Reactive] FooClass Foo { get; set; } = new FooClass();
void PrintList<T> (IEnumerable<T> items)
{
foreach (T item in items)
{
Console.WriteLine(item.ToString());
}
}
public ViewModel()
{
Console.WriteLine("=== ===");
SourceList<FooClass> sl2 = new SourceList<FooClass>();
FooClass fo1 = new FooClass() { Bar = new BarClass("Hello ") };
FooClass fo2 = new FooClass() { Bar = new BarClass("World ") };
FooClass fo3 = new FooClass() { Bar = new BarClass("Out ") };
FooClass fo4 = new FooClass() { Bar = new BarClass("There ") };
FooClass fo5 = new FooClass() { Bar = new BarClass("!!!!!!") };
sl2.Add(fo1);
sl2.Add(fo2);
sl2.Add(fo3);
sl2.Add(fo4);
sl2.Connect()
.Transform(x => x.Bar.Baz)
.Bind(out ReadOnlyObservableCollection<String> transformed)
.Subscribe( x=> { Console.WriteLine("CHANGE from Subscribe"); } );
Console.WriteLine("=== Start ===");
((INotifyCollectionChanged)transformed).CollectionChanged +=
new NotifyCollectionChangedEventHandler(( s,e) => Console.WriteLine("CHANGE from Event Handler"));
Console.WriteLine("sl2: ");
PrintList<FooClass>(sl2.Items);
Console.WriteLine("transformed: ");
PrintList<String>(transformed);
Console.WriteLine("=== Send to Space ===");
fo2.Bar.Baz = "Space";
Console.WriteLine("sl2: ");
PrintList<FooClass>(sl2.Items);
Console.WriteLine("transformed: ");
PrintList<String>(transformed);
Console.WriteLine("=== Add !!!! ===" );
sl2.Add(fo5);
Console.WriteLine("sl2: ");
PrintList<FooClass>(sl2.Items);
Console.WriteLine("transformed: ");
PrintList<String>(transformed);
Console.WriteLine("=== ===");
Console.WriteLine("Finish");
Console.ReadLine();
}
}
class Program
{
static void Main(string[] args)
{
ViewModel vm = new ViewModel();
}
}
}
结果不是我所希望的。似乎 .Transform(x => x.Bar.Baz)
仅转发从列表“sl2”中添加或删除的更新项目。如果 Bar.Baz
的值发生更改,这些更改不会转发到 transformed
。
我的输出是:
=== ===
CHANGE from Subscribe
=== Start ===
sl2:
Hello
World
Out
There
transformed:
Hello
World
Out
There
=== Send to Space ===
sl2:
Hello
Space
Out
There
transformed:
Hello
World <--- I would have hoped to have 'Space' here
Out
There
=== Add !!!! ===
CHANGE from Event Handler <-- I would have hoped that event handlers are triggered at World->Space
CHANGE from Subscribe <-- I would have hoped that event handlers are triggered at World->Space
sl2:
Hello
Space
Out
There
!!!!!!
transformed:
Hello
World <--- I would have hoped to have 'Space' here
Out
There
!!!!!!
=== ===
Finish
请注意:
(1) 在transformed
中,世界->空间的变化从未完成。在 sl2
中,此更改已完成。
(2)CollectionChangedEvent只有在添加了item添加后才会触发。
我的问题:
如何确保transform()
设置正确的通知?
更新
根据下面的 Funk 答案,应该通过以下方式修复此问题:
sl2.Connect()
.AutoRefresh(x => x.Bar.Baz)
.Transform(x => x.Bar.Baz)
...
但是这不会改变输出。
最佳答案
Is this expected behaviour?
是的。符合ObservableCollection<T>
仅监视集合(或流)的更改。
当然,您想要的东西很常见,而且幸运的是,很容易实现。来自 ReactiveUI documentation :
DynamicData supports change tracking for classes that implement the INotifyPropertyChanged interface — ReactiveObjects. For example, if you'd like to do a WhenAnyValue on each element in a collection of changing objects, use the AutoRefresh() DynamicData operator
只需添加 AutoRefresh
运算符(operator)到管道并使用 Transform
接受要设置的标志的运算符重载 transformOnRefresh
为真。
sl2.Connect()
.AutoRefresh(x => x.Bar.Baz)
.Transform(x => x.Bar.Baz, true)
...
<小时/>
为了帮助调试,您可以分解 IChangeSet<string>
及其 Change<string>
s。
sl2.Connect()
.AutoRefresh(x => x.Bar.Baz)
.Transform(x => x.Bar.Baz, true)
.Do(x =>
{
foreach (var c in x) Console.WriteLine($"sl2 ticks {c.Item.Current}");
})
...
关于c# - ReactiveUI:IObservable.Transform() 不转发通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60552423/