在线的大多数示例(如果不是全部)都将注册处理程序,但随后会返回一个离散的Observable值(即Observable.Return(RecoveryOptionResult.CancelOperation))。对于正确的实现,最好将RecoveryOptions列表作为按钮(或类似内容)的列表呈现给用户,并将流控制传递给用户。

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

我设法一起破解了一些东西,但是我无法想象这种方式是正确的。我缺乏使用reactui的经验,这使我无法概念化监视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值。但是,似乎必须有更好的方法来做到这一点。

最佳答案

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

通过执行以下操作,我们可以调整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/

10-08 22:46