How do you use asynchronous UserError handlers

Most (if not all) examples online register a handler, but then return a discrete observable (i.e. Observable.Return(RecoveryOptionResult.CancelOperation)

). For correct implementation, it is best to present the list to the RecoveryOptions

user as a list of buttons (or something similar) and pass control of the flow to the user.

What I am struggling with is waiting for the user to press a button (or more specifically, how to wait for one of the commands RecoveryOption

to have its set RecoveryResult

).

I have managed to hack something together that does this, but I cannot imagine this is correct. My lack of experience using reactiveui prevents me from conceptualizing the correct way to monitor ReactiveList<IRecoveryCommand>

.

Below is my hacked code.

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

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

    // use ReactiveCommand 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();
}

      

The main problem is what is RecoveryResult

not observable. So I have to track IsExecuting

to be observable and then check the value RecoveryResult

. It seems, however, that there must be a better way to do this.

+3


source to share


1 answer


Looking at it again today, I noticed that the reason why I can not watch RecoveryResult

, is that RecoveryOptions

- is ReactiveList<IRecoveryCommand>

and IRecoveryCommand

is not observed. An easy fix for this problem is to simply assume that all recovery options are in fact objects RecoveryCommand

(which are observables), but a more appropriate answer would be to create an observable stream based on a contract IRecoveryCommand

.

We can adapt the code described in the RxUI docs for recovery options to support RxUI 6.5 by doing the following:

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 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);
}

      



This extension method is required if you want to support any type IRecoveryCommand

, because it bases its observable stream on one of two observables it knows. However, if you can be sure that you are dealing with RecoveryCommand objects, you can do the following:

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);
}

      

I'll leave this answer until next, in the hope that @ paul-betts will confirm or deny it, an appropriate strategy.

+1


source







All Articles