c# - 如何异步使用 UserError 处理程序

标签 c# reactiveui

大多数(如果不是全部)在线示例注册一个处理程序,但随后返回一个离散的 Observable 值(即 Observable.Return(RecoveryOptionResult.CancelOperation) )。为了正确实现,最好提供 RecoveryOptions以按钮列表(或类似的东西)的形式向用户列出,并将流程控制传递给用户。

我正在苦苦挣扎的是如何等待用户点击按钮(或者更具体地说,如何等待 RecoveryOption 命令之一它的 RecoveryResult 集)。

我设法破解了一些的东西,但我无法想象这种方式是正确的。我缺乏使用 reactiveui 的经验使我无法概念化监视 ReactiveList<IRecoveryCommand> 的正确方法。 .

下面是我破解的代码。

// UserError.RegisterHandler(x => HandleErrorAsync(x));

private async Task<RecoveryOptionResult> HandleErrorAsync(UserError error)
{
    // present error UI...

    // use ReactiveCommand's IsExecuting observable to monitor changes (since RecoverResult is not an observable)
    // is there a better way to do this??? this seems sub-optimal
    await error.RecoveryOptions
        .Select(x => x.IsExecuting)
        .Merge()
        .Where(_ => error.RecoveryOptions.Any(x => x.RecoveryResult.HasValue))
        .FirstAsync();

    // recovery option was clicked in the UI

    // get the recovery option that was chosen
    return error.RecoveryOptions
        .Where(x => x.RecoveryResult.HasValue)
        .Select(x => x.RecoveryResult.Value)
        .First();
}

主要问题是 RecoveryResult 不可观察到。所以我必须监视 IsExecuting 可观察的,然后检查 RecoveryResult值(value)。然而,似乎必须有更好的方法来做到这一点。

最佳答案

今天再看这个,我注意到我无法观察到的原因RecoveryResult是因为RecoveryOptionsReactiveList<IRecoveryCommand>IRecoveryCommand是不可观察的。解决此问题的简单方法是假设所有恢复选项实际上都是 RecoveryCommand对象(可观察),但更合适的答案是基于 IRecoveryCommand 生成可观察流契约(Contract)。

我们可以修改 RxUI docs on Recovery Options 中描述的代码通过执行以下操作来支持 RxUI 6.5:

public static IObservable<RecoveryOptionResult> GetResultAsync(this UserError This, RecoveryOptionResult defaultResult = RecoveryOptionResult.CancelOperation)
{
    return This.RecoveryOptions.Any() ?
        This.RecoveryOptions
            .Select(x => x.IsExecuting
                .Skip(1) // we can skip the first event because it's just the initial state
                .Where(_ => x.RecoveryResult.HasValue) // only stream results that have a value
                .Select(_ => x.RecoveryResult.Value)) // project out the result value
            .Merge() // merge the list of command events into a single event stream
            .FirstAsync() : //only consume the first event
        Observable.Return(defaultResult);
}

如果您想支持任何类型的 IRecoveryCommand,则需要此扩展方法因为它的可观察流基于它所知道的仅有的两个可观察对象之一。但是,如果您可以确定您只是在处理 RecoveryCommand 对象,则可以改为执行以下操作:

public static IObservable<RecoveryOptionResult> GetResultAsync(this UserError This, RecoveryOptionResult defaultResult = RecoveryOptionResult.CancelOperation)
{
    return This.RecoveryOptions.Any() ?
        This.RecoveryOptions
            .Cast<RecoveryCommand>()
            .Select(x => x // our command is now observable
                // we don't Skip(1) here because we're not observing a property any more
                .Where(_ => x.RecoveryResult.HasValue)
                .Select(_ => x.RecoveryResult.Value))
            .Merge()
            .FirstAsync() :
        Observable.Return(defaultResult);
}

我会把这个答案留到下一次,希望 @paul-betts 可以确认或否认这是合适的策略。

关于c# - 如何异步使用 UserError 处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30655784/

相关文章:

c# - 如何使用 CaSTLe Windsor 的 CollectionResolver 避免循环行为?

C# 列表仅包含

architecture - 使用 Xamarin Forms 和 ReactiveUI 进行最先进的导航和路由

c# - 如何异步执行 WhenAnyValue 委托(delegate)?

c# - ObserveOn 与修改代码以在主线程上运行

c# - 使用 Web API 的模型绑定(bind)接口(interface)属性

c# - 根据最晚日期从 IGrouping 中获取项目

c# - 在 ReactiveUI 中取消/忽略 ReactiveAsyncCommand 的结果

c# - ReactiveUI WPF - 调用线程无法访问此对象,因为另一个线程拥有它

c# - .NET 中的堆栈与堆