Как обновить значение CanExecute после объявления ReactiveCommand - PullRequest
1 голос
/ 21 октября 2019

Я использую ReactiveUI с AvaloniaUI, и у меня ViewModel с несколькими ReactiveCommands, а именно: Сканирование, Загрузка и Выполнение.

Сканирование вызывается при обновлении Observable<string> (когда я получаюштрих-код со сканера).

Загрузка запускается из команды сканирования.

Запуск запускается с помощью кнопки в пользовательском интерфейсе.

Упрощенный код ниже:

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 продолжит выполняться при выполнении другой команды.

Есть ли лучший / правильный способ реализации этого?

1 Ответ

2 голосов
/ 21 октября 2019

Но я не могу ссылаться на свойство IsExecuting команд, пока оно не было объявлено.

Один из вариантов - использовать Subject<T>, передать его в качестве параметра canExecute: команде, а затем выдать новые значения, используя OnNext для 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).

...