【问题标题】:How do you update the CanExecute value after the ReactiveCommand has been declared声明 ReactiveCommand 后如何更新 CanExecute 值
【发布时间】:2020-02-17 03:33:18
【问题描述】:

我正在使用 ReactiveUIAvaloniaUI,并且有一个带有多个 ReactiveCommands 的 ViewModel,即扫描、加载和运行。

Observable<string> 更新时调用扫描(当我从扫描仪收到条形码时)。

从扫描命令中触发加载。

从 UI 上的按钮触发运行。

下面的简化代码:

var canRun = Events.ToObservableChangeSet().AutoRefresh().ToCollection().Select(x => x.Any());
Run = ReactiveCommand.CreateFromTask<bool>(EventSuite.RunAsync, canRun);

var canLoad = Run.IsExecuting.Select(x => x == false);
var Load = ReactiveCommand.CreateFromTask<string, Unit>(async (barcode) =>
    {
        //await - go off and load Events.
    }, canLoad);

var canReceiveScan = Load.IsExecuting.Select(x => x == false)
        .Merge(Run.IsExecuting.Select(x => x == false));
var Scan = ReactiveCommand.CreateFromTask<string, Unit>(async (barcode) => 
    {
        //do some validation stuff
        await Load.Execute(barcode)
    }, canReceiveScan);

Barcode
   .SubscribeOn(RxApp.TaskpoolScheduler)
   .ObserveOn(RxApp.MainThreadScheduler)
   .InvokeCommand(Scan);

每个命令只有在没有其他命令正在运行(包括它自己)时才能执行。但是我不能在声明之前引用命令的IsExecuting 属性。所以我一直在尝试像这样合并“CanExecute”可观察变量:

canRun = canRun
   .Merge(Run.IsExecuting.Select(x => x == false))
   .Merge(Load.IsExecuting.Select(x => x == false))
   .Merge(Scan.IsExecuting.Select(x => x == false))
   .ObserveOn(RxApp.MainThreadScheduler);

// same for canLoad and canScan

我遇到的问题是,当另一个命令正在执行时,ReactiveCommand 将继续执行。

有没有更好/正确的方法来实现这个?

【问题讨论】:

    标签: mvvm reactiveui avaloniaui


    【解决方案1】:

    但我不能在声明之前引用命令的 IsExecuting 属性。

    一种选择是使用Subject&lt;T&gt;,将其作为canExecute: 参数传递给命令,然后在Subject&lt;T&gt; 上使用OnNext 发出新值。

    另一种选择是使用WhenAnyObservable

    this.WhenAnyObservable(x => x.Run.IsExecuting)
        // Here we get IObservable<bool>,
        // representing the current execution 
        // state of the command.
        .Select(executing => !executing)
    

    然后,您可以将Merge 运算符应用于WhenAnyObservable 生成的observables。要跳过初始空值(如果有),请使用 Where 运算符或 .Skip(1)

    【讨论】:

      【解决方案2】:

      举一个Artyom的答案中描述的Subject&lt;T&gt;选项的例子,这里是受Kent Boogaartbook p的启发。 82:

      var canRun = new BehaviorSubject<bool>(true);
      
      Run = ReactiveCommand.Create...(..., canExecute: canRun);
      Load = ReactiveCommand.Create...(..., canExecute: canRun);
      Scan = ReactiveCommand.Create...(..., canExecute: canRun);
      
      Observable.Merge(Run.IsExecuting, Load.IsExecuting, Scan.IsExecuting)
          .Select(executing => !executing).Subscribe(canRun);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多