异步命令ReactiveUI从4.6.1迁移到7.0

时间:2016-05-16 14:04:08

标签: c# wpf system.reactive reactiveui

如何将其从7.0转换为ReactiveCommand:

private void SetCanRunProcessCommand()
{
    _runProcessCommand = new ReactiveAsyncCommand(CanRunProcess(null));
    _runProcessCommand.RegisterAsyncAction(RunProcess);

    _runProcessCommand.ThrownExceptions.Subscribe(OnError);

    _runProcessCommand.AsyncStartedNotification.Subscribe(_ => IsBusy = true);

    _runProcessCommand.AsyncCompletedNotification.Subscribe(x => IsBusy = false);
    _runProcessCommand.AsyncCompletedNotification.Subscribe(_ => PerformPostRunImpl());
}

以下是我的尝试:

private void SetCanRunProcessCommand()
{
    _runProcessCommand = ReactiveCommand.CreateFromTask((x) => Run(x), CanRunProcess(null));
    _runProcessCommand.IsExecuting.ToProperty(this, x => x.IsBusy);

    _runProcessCommand.ThrownExceptions.Subscribe(OnError);
}

private async Task Run(object param)
{
    try
    {
        await RunProcess(param);
    }
    finally
    {
        PerformPostRunImpl();
    }
}

这种方法的问题在于我现在无法控制调度程序。当我测试代码时,我无法使用TestScheduler及时向前移动,因为代码不依赖于调度程序。

第二种方法是通过调度程序将ReactiveCommand.CreateRxApp.ThreadPoolScheduler一起使用,这将是单元测试中的CurrentThread。这就是我要做的,但还有其他问题。

  1. 看起来调度程序并不控制RunProcess(它总是在主线程上调用)。我认为ReactiveCommand.Create(function)在之前的版本中与此相同:
  2. 代码:

    var command = ReactiveCommand.Create();
    command.Subscribe(function);
    

    但这不是因为第二次通话是由调度程序控制的。

    1. 这会产生另一个问题,因为RunProcess包含一些需要在UI线程上进行的调用,因此我将得到跨线程异常。它在4.6.1 ReactiveUI中是如何工作的?我怎样才能回到那种行为?

    2. 如何在RunProcess之后执行操作?最后似乎没有用。

    3. 简单示例:

      public bool Validation()
      {
        return isValid(); Background
      }
      
      public void RunProcess()
      {
        LongRunning(); // Background 
      }
      
      public void SetEverythingIsCorrect()
      {
         State = Success; // UI
      }
      

      我需要创建一个ReactiveCommand,它将在不同的调度程序上调用这3个方法。在测试中,我想使用TestScheduler,所以一切都应该是单线程的。像这样:

      new TestScheduler().With(sched =>
      {
          Abc a = new Abc(_dialogService, _fileSystemHelper);
          a.RunProcessCommand.Execute();
          sched.AdvanceBy(1000);
      
          Assert.AreEqual(State.Success, a.State);
      });
      

      验证时,应调用RunProcess TaskPoolScheduler 应该在MainThreadScheduler上调用SetEverythingIsCorrect。

      我的最后一种方法与此类似:

      protected internal async Task RunProcess(object obj)
      {
          await Observable.Start(Validation, RxApp.TaskpoolScheduler)
                          .Concat(Observable.Start(() => RunProcess(obj), RxApp.TaskpoolScheduler))
                          .Concat(Observable.Start(SetEverythingIsCorrect, RxApp.MainThreadScheduler))
                          .Finally(() =>
                          {
                              PerformPostRunImpl();
                              IsBusy = false;
                          });
      }
      
      _runProcessCommand = ReactiveCommand.CreateFromTask(() => RunProcess(null), CanRunProcess(null));
      

0 个答案:

没有答案