3

我正在使用ReactiveUIAvaloniaUI拥有一个 ViewModel,其中ReactiveCommands包括 Scan、Load 和 Run。

更新时调用扫描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 将在另一个命令执行时继续执行。

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

4

2 回答 2

4

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

一种选择是使用 a Subject<T>,将其作为canExecute:参数传递给命令,然后使用OnNexton发出新值Subject<T>

另一种选择是使用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. 要跳过初始空值(如果有),请使用Where运算符或.Skip(1).

于 2019-10-21T07:43:48.337 回答
1

举一个ArtyomSubject<T>回答中描述的选项的例子,这里是受Kent Boogaartp 启发的东西。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);
于 2020-04-23T10:53:45.143 回答