ReactiveUI异常处理 [英] ReactiveUI exception handling
问题描述
我已经查看了许多ReactiveUI示例,但是我看不到一个如何处理异常的好简单示例,在该示例中应该向用户显示一条消息.(如果有一个很好的例子,有人可以指出吗?).
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 user. (If there is a good example can somebody point me to it?).
我的第一个问题是如何使用ReactiveCommand和ToProperty处理异常.例如,我有以下代码:
My first question is how to handle an exception with ReactiveCommand and ToProperty. For example, I have the following code:
public class MainWindowViewModel : ReactiveObject
{
public ReactiveCommand CalculateTheAnswer { get; set; }
public MainWindowViewModel()
{
CalculateTheAnswer = new ReactiveCommand();
CalculateTheAnswer
.SelectMany(_ => AnswerCalculator())
.ToProperty(this, x => x.TheAnswer);
CalculateTheAnswer.ThrownExceptions
.Select(exception => MessageBox.Show(exception.Message));
}
private readonly ObservableAsPropertyHelper<int> _theAnswer;
public int TheAnswer
{
get { return _theAnswer.Value; }
}
private static IObservable<int> AnswerCalculator()
{
var task = Task.Factory.StartNew(() =>
{
throw new ApplicationException("Unable to calculate answer, because I don't know what the question is");
return 42;
});
return task.ToObservable();
}
}
我认为我一定会误解ThrownExceptions,因为当我运行上面的代码时,这个可观察的对象没有收到任何物品.我在做什么错了?
I think I must be misunderstanding ThrownExceptions, because this observable is not receiving any items when I run the code above. What am I doing wrong?
我的第二个问题是如何以对MVVM友好的方式执行此操作.此博客条目提到了用户错误功能,但我找不到有关如何使用它的任何文档.我如何在上面的示例中实现它?
My second question is how would I do this in a MVVM-friendly way. This blog entry mentions a User Errors feature, but I can't find any documentation on how to use it. How would I implement it into the above example?
Edit: I've published an example solution on github based on Paul's answer below.
推荐答案
您正在了解 ThrownExceptions
,但是它是错误的人, _theAnswer.ThrownExceptions
将收到例外.但棘手的是,现在该按钮不再起作用-一旦Observable结束OnError,它就永远做好了.
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);
在这种情况下, ReactiveAsyncCommand
要容易得多,因为每次调用都会创建一个新的 IObservable
,因此您可以这样做:
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"));
如何使用UserError
因此, UserError
就像是旨在向用户抛出的异常(即,它包含友好的文本,而不是程序员的文本)
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)
要使用 UserError
,您必须做两件事-首先,更改ThrownExceptions:
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 */);
然后在您的View代码后面,调用`RegisterHandler:
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);
这篇关于ReactiveUI异常处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!