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
vsObserveOn
of evenObserveOnDispatcher
or thescheduler:
parameter ofToProperty
? - 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 sureSelect
is even needed, to be frank. - I have seen some examples that set the
Binding.IsAsync
totrue
, 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
andThreadPriority
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.