声明 ReactiveCommand 后如何更新 CanExecute 值
How do you update the CanExecute value after the ReactiveCommand has been declared
我正在将 ReactiveUI
与 AvaloniaUI
一起使用,并且有一个包含多个 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 将继续执行。
有没有 better/correct 方法来实现这个?
But I can't reference the commands' IsExecuting property before is it declared.
一个选项是使用 Subject<T>
,将其作为 canExecute:
参数传递给命令,然后使用 Subject<T>
上的 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
生成的可观察值。要跳过初始空值(如果有),请使用 Where
运算符或 .Skip(1)
.
以 , here is something inspired by Kent Boogaart's book p 的答案中描述的 Subject<T>
选项为例。 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);
我正在将 ReactiveUI
与 AvaloniaUI
一起使用,并且有一个包含多个 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 将继续执行。
有没有 better/correct 方法来实现这个?
But I can't reference the commands' IsExecuting property before is it declared.
一个选项是使用 Subject<T>
,将其作为 canExecute:
参数传递给命令,然后使用 Subject<T>
上的 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
生成的可观察值。要跳过初始空值(如果有),请使用 Where
运算符或 .Skip(1)
.
以 Subject<T>
选项为例。 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);