我想在发生错误时显示带有两个按钮的警告对话框。 据我所知,这是使用Interaction属性的方法:
this.ViewModel.ConnectionError.RegisterHandler(interaction =>
{
var retry = await this.DisplayAlert("Connection failed", "Do you want to retry?", "RETRY", "ABORT");
if (retry)
interaction.SetOutput(DevicesViewModel.ErrorRecoveryOption.Retry);
else
interaction.SetOutput(DevicesViewModel.ErrorRecoveryOption.Abort);
});
问题是异常是在第三方库中的线程内引发的。必须在主线程中调用DisplayAlert。我尝试了以下方法:
this.ViewModel.ConnectionError.RegisterHandler(interaction =>
{
RxApp.MainThreadScheduler.ScheduleAsync(interaction, async (scheduler, i, cancelationToken) =>
{
this.Log().Debug("ScheduleAsync");
var retry = await this.DisplayAlert("Connection failed", "Do you want to retry?", "RETRY", "ABORT");
if (retry)
i.SetOutput(DevicesViewModel.ErrorRecoveryOption.Retry);
else
i.SetOutput(DevicesViewModel.ErrorRecoveryOption.Abort);
return Disposable.Empty;
});
});
我可以在控制台中看到日志消息,但对话框没有显示,应用程序在ReactiveUI.dll内崩溃。 我做错了什么?
答案 0 :(得分:1)
如果您检查崩溃的详细信息,我怀疑您会发现它抱怨没有任何处理交互。原因是您的注册处理程序是同步的。当然,它会启动异步工作,但是您没有给ReactiveUI任何等待该工作完成的方法。
您可以通过查看通过呼叫解决的RegisterHandler(Action<InteractionContext<TInput, TOutput>>)
超载来验证这一点。你会发现它RegisterHandler
。换句话说,&#34;注册一个处理器,它接受上下文并同步处理交互。
您要做的是调用异步RegisterHandler(Func<InteractionContext<TInput, TOutput>, Task>)
方法之一:
RegisterHandler(Func<InteractionContext<TInput, TOutput>, IObservable<Unit>>)
this
.ViewModel
.ConnectionError
.RegisterHandler(
context =>
Observable
.Start(
() => Unit.Default,
RxApp.MainThreadScheduler)
.SelectMany(_ => this.DisplayAlert("Connection failed", "Do you want to retry?", "RETRY", "ABORT"))
.Do(result => context.SetOutput(result ? ErrorRecoveryOption.Retry : ErrorRecoveryOption.Abort)));
为此编写逻辑有多种方法。我倾向于选择Rx作为表达异步的手段,所以我这样写:
Observable.Start
Handle
电话会让我们找到正确的话题,而且如果我是你,我还会考虑如何清理它。具体来说,我看看在正确的线程上发起交互。也就是说,无论调用Handle
(可能是您的VM)都应该在UI线程上执行此操作。尽管您有责任在正确的线程上执行命令,{{1}}也是如此。