Миграция асинхронной команды ReactiveUI с 4.6.1 на 7.0

Как я могу преобразовать это в ReactiveCommand из 7.0:

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.Create с RxApp.ThreadPoolScheduler который будет CurrentThread в модульных тестах. И вот как я бы это сделал, но есть и другие проблемы.

  1. Похоже, что планировщик не контролирует RunProcess (он всегда вызывается в основном потоке). я думал так ReactiveCommand.Create(function) равно этому в предыдущей версии:

Код:

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

Но это не потому, что второй вызов контролируется планировщиком.

  1. Это создаст еще одну проблему, потому что RunProcess содержит некоторые вызовы, которые необходимо выполнить в потоке пользовательского интерфейса, поэтому я получу исключение между потоками. Как это работает в 4.6.1 ReactiveUI? Как я могу вернуться к такому поведению?

  2. Как мне выполнить операцию после RunProcess? Наконец-то, похоже, не работает.

Простой пример:

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 SetEverythingIsCorrect должен быть вызван на MainThreadScheduler.

Мой последний подход был чем-то похожим на это:

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 ответов

Другие вопросы по тегам