使用ReactiveUI按顺序执行一组命令

时间:2018-06-26 15:08:56

标签: c# .net mvvm reactiveui

我有一个ViewModel,其中有一些ReactiveCommands用户可以手动调用。

CommandA
CommandB
CommandC

因此,用户只能先调用 B A ,然后再调用 C

问题在于,我想创建另一个命令来按顺序运行它们(从A到C)。它们不应该并行运行,而是顺序 >。

如何命令给定特征?

3 个答案:

答案 0 :(得分:3)

由于您希望它们顺序执行,因此ReactiveCommand.CreateCombined并不是一个很好的选择。但是,您可以创建类似于CombinedReactiveCommand的内容以适合您的情况。

可以通过调用ReactiveCommand<TParam,TResult>.Execute手动执行反应性命令,该方法返回一个返回单个值的IObservable<TResult>。因此,一个非常基本的实现可以通过SelectMany将其链接到其他执行调用:

ReactiveCommand.CreateFromObservable(() =>
    CommandA.Execute()
        .SelectMany(_ => CommandB.Execute())
        .SelectMany(_ => CommandC.Execute()));

如果所有命令都具有相同的类型,则可以使其更通用:

var commands = new[] { CommandA, CommandB, CommandC };
ReactiveCommand.CreateFromObservable(() =>
    commands.Aggregate(
        Observable.Return(Unit.Default),
        (acc, cur) => acc.SelectMany(_ => cur.Execute())));

但是,这没有考虑CombinedReactiveCommand处理的其他内容,例如CanExecuteThrownExceptions。如果需要处理这些问题,则可以考虑使用自己的CombinedReactiveCommand。

答案 1 :(得分:1)

导入System.Reactive.Linq,现在您可以:

{
    await CommandA.Execute();
    await CommandB.Execute();
    await CommandC.Execute();
}

System.Reactive.Linq使IObservable处于等待状态。

答案 2 :(得分:0)

我正在假设您的命令的类型为ReactiveCommand<Unit,Unit>,因此,您可以执行以下操作:

public class MyCoolViewModel
{
   bool runSequentially = false;

   public ReactiveCommand<Unit, Unit> Command { get; set; }
   public ReactiveCommand<Unit, Unit> Command2 { get; set; }
   public ReactiveCommand<Unit, Unit> Command3 { get; set; }
   public ReactiveCommand<Unit, Unit> CommandwhoInvokesOtherCommands { get; set; }


   public MyCoolViewModel()
   {

       Command = ReactiveCommand.CreateFromTask<Unit, Unit>(async _ =>
       {    
        runSequentially= false;
        Console.WriteLine("Start 1");
        await Task.Delay(1000);
        Console.WriteLine("End 1");
        return Unit.Default;
       });
      Command2 = ReactiveCommand.CreateFromTask<Unit, Unit>(async _ =>
      {
        runSequentially = false;
        Console.WriteLine("Start 2");
        await Task.Delay(1000);
        Console.WriteLine("End 2");
        return Unit.Default;
      });

    Command3 = ReactiveCommand.CreateFromTask<Unit, Unit>(async _ =>
    {
        Console.WriteLine("Start 3");
        await Task.Delay(1000);
        Console.WriteLine("End 3");
        return Unit.Default;
    });

    CommandwhoInvokesOtherCommands = ReactiveCommand.CreateFromTask<Unit, Unit>(async _ =>
      {
          Console.WriteLine("Invoking other commands");
          runSequentially = true;
          await Task.Delay(1000);
          Console.WriteLine("End");
          return Unit.Default;
      });

            /*Command 1, 2 and 3 only will run if flag is set to true*/
    CommandwhoInvokesOtherCommands.Where(_ => runSequentially).InvokeCommand(Command);
    Command.Where(_ => runSequentially).InvokeCommand(Command2);
    Command2.Where(_ => runSequentially).InvokeCommand(Command3);

    //Observable.Return(Unit.Default).InvokeCommand(CommandwhoInvokesOtherCommands);//for test purposes

}
}

实用程序方法InvokeCommand将在命令返回时调用另一个命令,因此该方法加上where子句即可解决问题。

希望对您有所帮助 问候