Але*_*вой 2 linq reactive-programming system.reactive reactiveui
关于 ReactiveUi 的另一个问题。我有一个用于编辑表单的 ViewModel。模型是 ReactiveObject。我只想在对象发生更改时启用 savecommand。我的尝试:
var canSaveCommand =
this.WhenAnyValue(vm => vm.CurrentClient)
.Where(client => client != null)
.Select(client =>
client.Changed
)
.Any();
Run Code Online (Sandbox Code Playgroud)
但是当表单出现时SaveCommand已经启用了。我的错在哪里?
您想使用Switch而不是 SelectMany。SelectMany 不会取消订阅以前的客户端。它将合并来自所有客户端的事件。在订阅下一个之前切换取消订阅前一个客户端。
var canSaveCommand =
this.WhenAnyValue(vm => vm.CurrentClient)
.Where(client => client != null)
.Select(client =>
client.Changed
)
.Switch()
.Any();
Run Code Online (Sandbox Code Playgroud)
例如下面的代码就清楚了。假设我们有一个名为AudioChannelIt的类,它生成我们可以处理并发送到扬声器的音频帧。
public class IAudioChannel {
public IObservable<AudioFrame> AudioFrameObservable {get;}
}
Run Code Online (Sandbox Code Playgroud)
然后我们可能有一个用户可以选择的音频节点列表,但我们只想要最新的发送音频到扬声器。下面的类使当前选择的音频节点作为可观察对象可用。
public class AudioListViewModel {
public class IObservable<IAudioChannel> CurrentAudioChannelObservable {get;}
}
Run Code Online (Sandbox Code Playgroud)
现在考虑以下代码
AudioListViewModel viewModel;
viewModel
.CurrentAudioChannelObservable
.SelectMany(current=>current.AudioFrameObservable)
.Subscribe(frame=>frame.Play());
Run Code Online (Sandbox Code Playgroud)
对比
AudioListViewModel viewModel;
viewModel
.CurrentAudioChannelObservable
.Select(current=>current.AudioFrameObservable)
.Switch()
.Subscribe(frame=>frame.Play());
Run Code Online (Sandbox Code Playgroud)
在第一个版本中,随着我们更改音频节点的选择,我们添加了越来越多的订阅。音频输出很快就变成一堆乱七八糟的混合通道。在第二个版本中,一次只订阅一个频道,音频输出仅播放来自单个频道的输出。
许多人在开始使用 RX 时都会犯这个错误。例如,我在 ReactiveUI 框架中发现了一个使用 SelectMany 而不是 Switch 的错误。
在 ReactiveUI 中有一个内置的方式来以清晰的方式实现这一点
实际上还有另一种方法可以实现你想要的,我会把它放在另一个答案中,只是为了向你展示如何使用 ReactiveUI。
var canSaveCommand =
this
.WhenAnyObservable(vm => vm.CurrentClient.Changed)
.StartWith(false);
Run Code Online (Sandbox Code Playgroud)
请注意,虽然您应该以false开头以确保在没有可观察的值开始时存在值,但不必显式处理 null 。
WhenAnyObservable 的行为很像 Rx 运算符 CombineLatest,因为它监视一个或多个 observable,并允许您根据每个的最新值定义投影。WhenAnyObservable 与CombineLatest 的不同之处在于它的参数是表达式,而不是对目标observable 的直接引用。这种差异的影响是 WhenAnyObservable 设置的 watch 与订阅时存在的特定 observable 实例无关。也就是说,表达式所指向的 observable 可以在后面替换,并且新的 observable 的结果仍然会被捕获。这可以派上用场的一个例子是当视图想要观察视图模型上的 observable,但视图模型可以在视图的生命周期内被替换。无需在每次更改视图模型后重新订阅目标可观察对象,您可以使用 WhenAnyObservable 指定要观看的“路径”。这允许您在视图中使用单个订阅,而不管目标视图模型的生命周期如何。
| 归档时间: |
|
| 查看次数: |
689 次 |
| 最近记录: |