ReactiveUI exception handling

后端 未结 1 1470
滥情空心
滥情空心 2020-12-23 23:05

I\'ve looked around at a number of the ReactiveUI samples, but I can\'t see a good simple example of how to handle exceptions, where a message should be displayed to the use

相关标签:
1条回答
  • 2020-12-23 23:56

    You're understanding ThrownExceptions, but it's on the wrong guy, _theAnswer.ThrownExceptions will receive the Exception. But the tricky part, is now that button doesn't work any more - once an Observable ends OnError, it's done for good.

    You end up having to do a few backflips here, something like:

    static IObservable<int?> AnswerCalculator()
    
    CalculateTheAnswer
        .SelectMany(_ => AnswerCalculator())
        .Catch(Observable.Return(null))
        .Where(x => x != null)
        .Select(x => x.Value)
        .ToProperty(this, x => x.TheAnswer);
    

    In this case, ReactiveAsyncCommand is much easier, since a new IObservable is created for every invocation, so you'd do:

    // ReactiveAsyncCommand handles exceptions thrown for you
    CalculateTheAnswer.RegisterAsyncTask(_ => AnswerCalculator())
        .ToProperty(this, x => x.TheAnswer);
    
    CalculateTheAnswer.ThrownExceptions.Subscribe(ex => MessageBox.Show("Aieeeee"));
    

    How to use UserError

    So, UserError is like an exception intended to be thrown at a user (i.e. it contains friendly text, not programmer text)

    To use UserError, you have to do two things - first, change your ThrownExceptions:

    CalculateTheAnswer.ThrownExceptions
        .SelectMany(ex => UserError.Throw("Something bad happened", ex))
        .Subscribe(result => /* Decide what to do here, either nothing or retry */);
    

    And in your View code-behind, call `RegisterHandler":

    UserError.RegisterHandler(err => {
        MessageBox.Show(err.ErrorMessage);
    
        // This is what the ViewModel should do in response to the user's decision
        return Observable.Return(RecoveryOptionResult.CancelOperation);
    });
    

    The cool part, is that this makes error dialogs testable - in a unit test:

    var fixture = new MainWindowViewModel();
    bool errorCalled;
    
    using (UserError.OverrideHandlersForTesting(_ => { errorCalled = true; return RecoveryOptionResult.CancelOperation })) { 
        CalculateTheAnswer.Execute(null);
    }
    
    Assert.True(errorCalled);
    
    0 讨论(0)
提交回复
热议问题