What's the appropriate way to use schedulers in derived properties to have a responsive UI?

Viewed 1687

I'm having a hard time trying to figure the proper way to schedule long-running reactive property "getters" in my ViewModel.

This excerpt from Intro to RX describes exactely what I want to do:

  • respond to some sort of user action
  • do work on a background thread
  • pass the result back to the UI thread
  • update the UI

Only in this case besides user interaction I want to react to change from other properties.

Below is the generic template I am using to get a derived property from an original property (in the actual code, there are chains of cascading derived properties).

In a Reactive ViewModel (inheriting from ReactiveObject) I already have some properties that derive from others. For exemple, when Original changes, Derived is recalculated.

    public TOriginal Original
    {
        get { return _original; }
        set { this.RaiseAndSetIfChanged(ref _original, value); }
    }
    TOriginal _original;


    public TDerived Derived { get { return _derived.Value; } }
    readonly ObservableAsPropertyHelper<double[,]> _derived;


    this.WhenAnyValue(x => x.Original)
        .Where(originalValue => originalValue != null)
        // ObserveOn? SubscribeOn? Which scheduler?
        .Select(derivedValue => LongRunningCalculation(originalValue))
        // Same thing here: ObserveOn? SubscribeOn? Which scheduler? 
        .ToProperty(this, x => x.Derived, out _derived); // should I use the `scheduler:` in this method?

My problems are: I have no idea how these different "design choices" should be combined to get my desired responsive UI:

  • Which scheduler to use? I have seen examples with RxApp.TaskpoolScheduler, RxApp.MainThreadScheduler, NewThreadScheduler.Default, and possibly others.
  • When to use SubscribeOn vs ObserveOn of even ObserveOnDispatcher or the scheduler: parameter of ToProperty?
  • Does the order make a difference? I have put the re-scheduling methods before and after the Select operator, but I'm not so sure. I'm not sure Select is even needed, to be frank.
  • I have seen some examples that set the Binding.IsAsync to true, but I tried it and haven't seem much difference, but again, maybe it is because of the other factors.
  • Are the concepts of SynchronizationContext and ThreadPriority relavant here? Is there a way to configure them in the code shown?
  • Should I be using ReactiveCommand or some other ReactiveUI class for this?

The most nerve-wrecking fact is that, with some combinations, the calculations work properly, but block the UI, while with some other combinations, the values are asynchronously calculated and the UI is a bit less blocked, but sometimes part of the derived values (in a collection of items, for example) are not available!

Sorry if I'm asking too much, but I didn't find any authoritative expected way to do what I need in the docs.

2 Answers
Related