从RxUi 7中的视图与ThrownExceptions进行交互的正确方式

本文关键字:交互 方式 RxUi 视图 ThrownExceptions | 更新日期: 2023-09-27 17:59:27

我正在尝试了解如何在RxUi 7中使用Interaction<TInput, TOutput>来显示确认警报。在阅读了这些文档后,我想到了这个:

ViewModel

public ReactiveCommand<Unit, Unit> Save { get; }
public Interaction<Exception, bool> ConfirmError;
Save
    .ThrownExceptions
    .Subscribe(ex => ConfirmError
                       .Handle(ex)
                       .Where(retry => retry == true)
                       .SelectMany(_ => Save.Execute(Unit.Default))
                       .Subscribe()
                       .AddTo(disposables))
    .AddTo(disposables);

查看

this
    .ViewModel
    .ConfirmError
    .RegisterHandler(async interaction =>
    {
        var retry = await DisplayAlert("Confirm", 
                                       $"Something went wrong: {interaction.Input.Message}. Do you want to retry?", 
                                       "Yes", 
                                       "No");
        interaction.SetOutput(retry);
    })
    .AddTo(disposables);

我的代码正在工作,但我不确定在确认完成时是否正确执行了命令。我还认为对于一个简单的提醒框来说,这太多的代码了,我正在寻找一种合适的方法来做到这一点。这怎么能简化呢?

第二个问题是:

如果我需要处理多个Exception类型(即:服务错误、连接错误),哪里是检查它的正确位置?

从RxUi 7中的视图与ThrownExceptions进行交互的正确方式

我认为您的代码基本上是可以的,除了一件事——您正在另一个Subscribe中执行Subscribe调用,IMO是一种代码气味。为了摆脱它,你可以写这样的东西:

Save
    .ThrownExceptions
    .SelectMany(ConfirmError.Handle)
    .Where(retry => retry == true)
    .SelectMany(_ => Save.Execute(Unit.Default))
    .Subscribe()
    .AddTo(disposables);

使用InvokeCommand助手:可以使其可读性略高(?)

Save
    .ThrownExceptions
    .SelectMany(ConfirmError.Handle)
    .Where(retry => retry == true)
    .Select(_ => Unit.Default)
    .InvokeCommant(Save)
    .AddTo(disposables);

注意:我没怎么玩RxUI 7.0,所以我把流改成一个包含单位的流是一个疯狂的猜测。

我还认为对于一个简单的警报框来说,代码太多了

这是一个警告框是一个重试逻辑。我不确定你是否能在RxUI中拥有比这简单得多的功能。

如果我需要处理多个异常类型(即:服务错误、连接错误),哪里是检查它的正确位置?

就我个人而言,我不会考虑异常类型,而是考虑与实际用户交互的方式。毕竟,你可能不想给他看堆栈的踪迹。

一种方法是为不同类型的与用户的交互(MessageInteractionYesNoInteraction等)提供单独的Interactions,这将允许您区分例如需要用户输入的操作和toast消息。另一种方法是将所有可能的问题定义为枚举(ConnectionTimeoutServiceError等),将可能的解决方案定义为另一个枚举(RetryAbort…),然后在ViewModel中有一个Interaction<ProblemEnum, ResolutionEnum>。这样,处理错误的代码将存储在一个地方。这种方法的缺点是处理逻辑将在视图中,因此测试起来会困难得多。

我建议你尝试并报告我的想法在实践中的效果:)