CanExecute取决于使用ReactiveUI的两个列表

本文关键字:两个 列表 取决于 ReactiveUI CanExecute | 更新日期: 2023-09-27 18:27:10

在我的应用程序中,我有一个带有两个列表的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)
    );
}

它确实有效,但我认为这种方法更像是变通方法。有更直接的解决方案可以吗?

CanExecute取决于使用ReactiveUI的两个列表

由于您可能需要侦听/响应内部对象的更改,ItemChanged可能是它能得到的最简单的(尽管相当重)。

不过也有一些评论:

  • 您可以避免可观察属性和whenAnyObservable调用,只需编写Print = ReactiveCommand.Create(selectingStream)

  • 注意,当您向列表中添加/删除元素时,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()扩展方法)

不是很简单,是吗?:)