Ответ 1
Вы понимаете ThrownExceptions
, но это не тот парень, _theAnswer.ThrownExceptions
получит Исключение. Но сложная часть, теперь эта кнопка больше не работает - как только Observable заканчивает OnError, это делается навсегда.
В итоге вам нужно сделать несколько обратных ссылок, например:
static IObservable<int?> AnswerCalculator()
CalculateTheAnswer
.SelectMany(_ => AnswerCalculator())
.Catch(Observable.Return(null))
.Where(x => x != null)
.Select(x => x.Value)
.ToProperty(this, x => x.TheAnswer);
В этом случае ReactiveAsyncCommand
намного проще, так как для каждого вызова создается новый IObservable
, поэтому вы должны:
// ReactiveAsyncCommand handles exceptions thrown for you
CalculateTheAnswer.RegisterAsyncTask(_ => AnswerCalculator())
.ToProperty(this, x => x.TheAnswer);
CalculateTheAnswer.ThrownExceptions.Subscribe(ex => MessageBox.Show("Aieeeee"));
Как использовать UserError
Итак, UserError
похоже на исключение, предназначенное для пользователя (т.е. содержит дружественный текст, а не текст программы)
Чтобы использовать UserError
, вам нужно сделать две вещи: сначала измените ThrownExceptions:
CalculateTheAnswer.ThrownExceptions
.SelectMany(ex => UserError.Throw("Something bad happened", ex))
.Subscribe(result => /* Decide what to do here, either nothing or retry */);
И в вашем кодовом коде View, вызывайте `RegisterHandler ':
UserError.RegisterHandler(err => {
MessageBox.Show(err.ErrorMessage);
// This is what the ViewModel should do in response to the user decision
return Observable.Return(RecoveryOptionResult.CancelOperation);
});
Классная часть состоит в том, что это позволяет проверить диалоги ошибок - в unit test:
var fixture = new MainWindowViewModel();
bool errorCalled;
using (UserError.OverrideHandlersForTesting(_ => { errorCalled = true; return RecoveryOptionResult.CancelOperation })) {
CalculateTheAnswer.Execute(null);
}
Assert.True(errorCalled);