Error418
Error418

Reputation: 309

Initial value of ObservableAsPropertyHelper when subscription is deferred

I recently started to use OAPH in my ViewModels.

To improve performance I'm using deferred subscription.

Given the following model class:

public class Model : ReactiveObject
{
    [ReactiveUI.Fody.Helpers.Reactive]
    public string Value { get; set; }
}

And the view model:

public class ViewModel : ReactiveObject
{
    private readonly Model _model;
    private readonly ObservableAsPropertyHelper<string> _propertyOAPH;

    public ViewModel(Model model)
    {
        this._model = model;
        this.WhenAnyValue(x => x._model.Value)
            .ToProperty(this, nameof(this.Property), out this._propertyOAPH, deferSubscription: true, scheduler: RxApp.MainThreadScheduler);
    }

    public string Property => this._propertyOAPH.Value;
}

The first time view model's property will be accessed, the source observable will be subscribed and the default OAPH value will be returned.

As in my example I'm using the WhenAnyValue extension method, the resulting observable will start with a value. Once this value is observed by the OAPH, the ViewModel will emit a PropertyChanged event.

var model = new Model { Value = "value" };
new ViewModel(model)
        .WhenAnyValue(x => x.Property)
        .Select(p => p ?? "null")
        .Subscribe(p => Console.WriteLine($" - ViewModel property: {p}"));

/**
* - ViewModel property: null
* - ViewModel property: value
*/

Is there a way for the OAPH initial value to be the first value of the source observable?

I understand that from a pure reactive perspective having the initial value temporarily null or wrong (if OAPH's initial value is set) is not an issue. But on iOS, TableViewCell height is calculated according to its content when initialized (if auto layout is used). TableViewVell height is not updated afterward.

I'm investigating first if there is an easy way to "solve" this problem with reactiveUI. If there is none, I'll investigate on a pure iOS solution.

Notes:

Upvotes: 0

Views: 1620

Answers (1)

Glenn Watson
Glenn Watson

Reputation: 2888

I was able to get this to work.

ViewModel.cs

        public ViewModel(Model model)
        {
            this._model = model;

            Observable.Defer(() => this.WhenAnyValue(x => x._model.Value)).ToProperty(this, nameof(this.Property), out this._propertyOAPH, deferSubscription: true, scheduler: RxApp.MainThreadScheduler);        }

I use Observable.Defer( will defer the evaluation of the property until the observable is subscribed.

Upvotes: 1

Related Questions