CanExecute 取决于使用 ReactiveUI 的两个列表
CanExecute depending on two lists using ReactiveUI
在我的应用程序中,我有一个包含两个列表的 ViewModel。还有一个动作CanExecute 属性 依赖于两个列表状态。我正在使用 ReactiveUI。到目前为止,我得到了以下(有效)实施:
public ReactiveList<Defect> Defects { get; } = new ReactiveList<Defect>();
public ReactiveList<State> States { get; } = new ReactiveList<State>();
public ReactiveCommand<object> Print { get; }
// this stream is artificial it is only needed to get notifications from both above
private IObservable<bool> SelectingStream { get; }
ctor()
{
Defects.ChangeTrackingEnabled = true;
States.ChangeTrackingEnabled = true;
SelectingStream = States.ItemChanged.CombineLatest(Defects.ItemChanged, (a, b) =>
{
// here is the condition that needs to be met in order to can execute action
return States.Count(s => s.IsSelected) == 1 &&
Defects.Any(d => d.IsActive);
});
Print = ReactiveCommand.Create(
this.WhenAnyObservable(x => x.SelectingStream)
);
}
它确实有效,但我认为这种方法更像是解决方法。可以吗,有更直接的解决方案吗?
因为您可能需要 listen/react 内部对象更改,ItemChanged
可能是最简单的(尽管相当繁重)。
虽然有些评论:
您可以避免可观察的 属性 和 whenAnyObservable
调用,只需编写 Print = ReactiveCommand.Create(selectingStream)
请注意,当您将 add/remove 个元素添加到列表中时,ItemChanged
将 不会 触发,因此您的可观察条件也应合并用列表 Changed
流来覆盖
您应该将 CombineLatest
替换为 Merge
以避免泄漏对象(您实际上不需要存储每个流的最新状态,a/b没用过)。
当您所依赖的属性以外的属性发生更改时,您可以避免触发检查
最终结果应该是这样的:
new [] {
States.Changed.SelectUnit(),
States.ItemChanged.Where(ea => ea.PropertyName == "IsSelected").SelectUnit(),
Defects.Changed.SelectUnit(),
Defects.ItemChanged.Where(ea => ea.PropertyName == "IsActive").SelectUnit() }
.Merge()
.Select(_ => States.Count(s => s.IsSelected) == 1 && Defects.Any(d => d.IsActive))
(使用方便的 SelectUnit()
扩展方法)
不是很简单,是吗? :)
在我的应用程序中,我有一个包含两个列表的 ViewModel。还有一个动作CanExecute 属性 依赖于两个列表状态。我正在使用 ReactiveUI。到目前为止,我得到了以下(有效)实施:
public ReactiveList<Defect> Defects { get; } = new ReactiveList<Defect>();
public ReactiveList<State> States { get; } = new ReactiveList<State>();
public ReactiveCommand<object> Print { get; }
// this stream is artificial it is only needed to get notifications from both above
private IObservable<bool> SelectingStream { get; }
ctor()
{
Defects.ChangeTrackingEnabled = true;
States.ChangeTrackingEnabled = true;
SelectingStream = States.ItemChanged.CombineLatest(Defects.ItemChanged, (a, b) =>
{
// here is the condition that needs to be met in order to can execute action
return States.Count(s => s.IsSelected) == 1 &&
Defects.Any(d => d.IsActive);
});
Print = ReactiveCommand.Create(
this.WhenAnyObservable(x => x.SelectingStream)
);
}
它确实有效,但我认为这种方法更像是解决方法。可以吗,有更直接的解决方案吗?
因为您可能需要 listen/react 内部对象更改,ItemChanged
可能是最简单的(尽管相当繁重)。
虽然有些评论:
您可以避免可观察的 属性 和
whenAnyObservable
调用,只需编写Print = ReactiveCommand.Create(selectingStream)
请注意,当您将 add/remove 个元素添加到列表中时,
ItemChanged
将 不会 触发,因此您的可观察条件也应合并用列表Changed
流来覆盖您应该将
CombineLatest
替换为Merge
以避免泄漏对象(您实际上不需要存储每个流的最新状态,a/b没用过)。当您所依赖的属性以外的属性发生更改时,您可以避免触发检查
最终结果应该是这样的:
new [] {
States.Changed.SelectUnit(),
States.ItemChanged.Where(ea => ea.PropertyName == "IsSelected").SelectUnit(),
Defects.Changed.SelectUnit(),
Defects.ItemChanged.Where(ea => ea.PropertyName == "IsActive").SelectUnit() }
.Merge()
.Select(_ => States.Count(s => s.IsSelected) == 1 && Defects.Any(d => d.IsActive))
(使用方便的 SelectUnit()
扩展方法)
不是很简单,是吗? :)