我查看了一些ReactiveUI示例,但是我看不到一个如何处理异常的简单示例,其中应该向用户显示消息.(如果有一个很好的例子可以有人指出我吗?).
我的第一个问题是如何使用ReactiveCommand和ToProperty处理异常.例如,我有以下代码:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
我想我必须误解ThrownExceptions,因为当我运行上面的代码时,这个observable没有收到任何项目.我究竟做错了什么?
我的第二个问题是如何以MVVM友好的方式执行此操作.此博客条目提到了用户错误功能,但我找不到有关如何使用它的任何文档.我将如何在上面的例子中实现它?
编辑:我已经根据Paul的回答在github上发布了一个示例解决方案.
Ana*_*tts 26
你理解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);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,ReactiveAsyncCommand更容易,因为IObservable为每次调用创建了一个new ,所以你要这样做:
// ReactiveAsyncCommand handles exceptions thrown for you
CalculateTheAnswer.RegisterAsyncTask(_ => AnswerCalculator())
.ToProperty(this, x => x.TheAnswer);
CalculateTheAnswer.ThrownExceptions.Subscribe(ex => MessageBox.Show("Aieeeee"));
Run Code Online (Sandbox Code Playgroud)
所以,UserError就像一个旨在抛出用户的异常(即它包含友好的文本,而不是程序员文本)
要使用UserError,您必须做两件事 - 首先,更改您的ThrownExceptions:
CalculateTheAnswer.ThrownExceptions
.SelectMany(ex => UserError.Throw("Something bad happened", ex))
.Subscribe(result => /* Decide what to do here, either nothing or retry */);
Run Code Online (Sandbox Code Playgroud)
在您的View代码隐藏中,调用`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);
});
Run Code Online (Sandbox Code Playgroud)
很酷的部分是,这使得错误对话框可以测试 - 在单元测试中:
var fixture = new MainWindowViewModel();
bool errorCalled;
using (UserError.OverrideHandlersForTesting(_ => { errorCalled = true; return RecoveryOptionResult.CancelOperation })) {
CalculateTheAnswer.Execute(null);
}
Assert.True(errorCalled);
Run Code Online (Sandbox Code Playgroud)