Linq 如何正确订阅已更改的反应对象序列?
关于ReactiveUi的另一个问题。我有一个用于编辑表单的ViewModel。模型是反应对象。我只想在对象发生更改时启用savecommand。我的尝试:Linq 如何正确订阅已更改的反应对象序列?,linq,system.reactive,reactive-programming,reactiveui,Linq,System.reactive,Reactive Programming,Reactiveui,关于ReactiveUi的另一个问题。我有一个用于编辑表单的ViewModel。模型是反应对象。我只想在对象发生更改时启用savecommand。我的尝试: var canSaveCommand = this.WhenAnyValue(vm => vm.CurrentClient) .Where(client => client != null) .Select(client =>
var canSaveCommand =
this.WhenAnyValue(vm => vm.CurrentClient)
.Where(client => client != null)
.Select(client =>
client.Changed
)
.Any();
但当窗体出现时,SaveCommand已启用。我的错误在哪里?尝试将您的选择更改为SelectMany。然后,这将为您提供一个可观察到的要传递到Any的更改,而不是一个可观察到的要传递到Any的更改。您希望使用not SelectMany。SelectMany不会从以前的客户端取消订阅。它将合并来自所有客户端的事件。交换机在订阅下一个客户端之前取消订阅上一个客户端
var canSaveCommand =
this.WhenAnyValue(vm => vm.CurrentClient)
.Where(client => client != null)
.Select(client =>
client.Changed
)
.Switch()
.Any();
例如,下面的代码说明了这一点。假设我们有一个叫做AudioChannel的类,它生成我们可以处理并发送给说话者的音频帧
public class IAudioChannel {
public IObservable<AudioFrame> AudioFrameObservable {get;}
}
vs
AudioListViewModel viewModel;
viewModel
.CurrentAudioChannelObservable
.Select(current=>current.AudioFrameObservable)
.Switch()
.Subscribe(frame=>frame.Play());
在第一个版本中,当我们更改音频节点的选择时,我们添加了越来越多的订阅。音频输出很快就会变成混合频道的乱七八糟。在第二个版本中,一次只订阅一个频道,音频输出仅播放单个频道的输出
很多人在开始使用RX时都会犯这个错误。例如,我发现一个使用SelectMany而不是Switch的
然而
在ReactiveUI中有一种内置的方式来以清晰的方式实现这一点
实际上,有另一种方法可以实现您想要的,我将把它放在另一个答案中,只是为了向您展示如何使用ReactiveUI
var canSaveCommand =
this
.WhenAnyObservable(vm => vm.CurrentClient.Changed)
.StartWith(false);
请注意,null不必显式处理,尽管您应该以false开头,以确保在没有可观测值可用时存在值
当任何可观测的行为非常像Rx运算符CombineTest时,在
它监视一个或多个可观察对象,并允许您定义
基于每个项目的最新值的投影。什么时候可以观察到
与CombineTest的不同之处在于其参数是表达式,
而不是直接引用目标可观测值。影响
这一区别在于,手表设置的时间不可观测
与发生时存在的特定可观察实例相关联
订阅也就是说,表达式指向的可观察对象可以
稍后将被替换,新的可观测结果仍将被替换
捕获。当视图
希望观察viewmodel上的可观察对象,但viewmodel可以
将在视图的生存期内被替换。而不是需要
每次更改viewmodel后,重新订阅可观察到的目标,
您可以使用WhenyObservable指定要监视的“路径”。这
允许您在视图中使用单个订阅,而不考虑
目标viewmodel的生命周期
SelectMany不会从以前的客户端取消订阅。它将合并来自所有客户端的事件,并导致一些讨厌的bug。Where之后的Take1将很快修复这些问题,但是,假设用户有一个场景,其中CurrentClient多次更改,而在许多场景中情况并非如此。如果您明确表示只有一个值可用,则最好使用Task ie提供方法Task GetClientAsync。对于属性,更安全的做法是假设它们总是可以更改的,如果它们在软件的v1中没有更改,那么在v9中它们可能会更改,并且您的假设会烧坏您。更改的问题是standart event wraper-IObservable,需要转换为bool。在我的例子中,我最终在VM HasChanges中添加了另一个可观察属性,并在任何.P.S的订阅中设置。对于WPF来说,ReactiveUI看起来很棒,但它有许多缺陷,并且隐含着奇异性。有时我想随地吐痰,然后离开他隐含的奇异性???…隐含的特殊性/特征。我还是不明白你的意思抱歉。你能举个例子吗。
AudioListViewModel viewModel;
viewModel
.CurrentAudioChannelObservable
.Select(current=>current.AudioFrameObservable)
.Switch()
.Subscribe(frame=>frame.Play());
var canSaveCommand =
this
.WhenAnyObservable(vm => vm.CurrentClient.Changed)
.StartWith(false);