Stuart
Stuart

Reputation: 65

ReactiveLIst ItemsAdded

Regarding ReactiveList, and the ItemsAdded property. I had a list of Journal items stored in a ReactiveList:

public ReactiveList<account.JournalViewModel> JournalEntries { get; private set; }

And I have a Readonly property to display the Balance of all the Journal Items:

readonly ObservableAsPropertyHelper<decimal> _balance;
public decimal Balance { get { return _balance.Value; } }

In the Constructor of the ViewModel, I instantiate the ReactiveList, and set the ObservableAsPropertyHelper:

this.JournalEntries = new ReactiveList<account.JournalViewModel>();
this.JournalEntries.ChangeTrackingEnabled = true;
this.WhenAnyObservable(vm => vm.JournalEntries.ItemsAdded)
    .Select(_ => this.JournalEntries.Sum(j => j.CreditAmount) - this.JournalEntries.Sum(j => j.DebitAmount))
    .ToProperty(this, vm => vm.Balance, out _balance);

Then, still in the constructor but further down, I add items to the ReactiveList:

foreach (var j in journalEntries)
     this.JournalEntries.Add(new account.JournalViewModel(j, this));

However this does not set the Balance property, and I don't know why. However if I change the property to a regular ol' Observable:

decimal _balance;
public decimal Balance { get { return _balance; } set { this.RaiseAndSetIfChanged(ref _balance, value); } }

And, in the constructor, Subscribe to the ItemsAdded Observable:

this.WhenAnyObservable(vm => vm.JournalEntries.ItemsAdded)
    .Subscribe(_ => this.Balance = this.JournalEntries.Sum(j => j.CreditAmount) - this.JournalEntries.Sum(j => j.DebitAmount));

When I add the Journal items, the desired result is achieved. I was hoping someone better skilled than I am could answer why the first method won't work. Is there a way to make it work that I am unaware of?

Upvotes: 1

Views: 484

Answers (1)

Charles Mager
Charles Mager

Reputation: 26213

What you've likely discovered is lazy subscription. ObservableAsPropertyHelper doesn't subscribe to the source observable until Value is accessed for the first time - this is a performance / memory optimisation.

As you probably don't access this during construction, the addition of items will have been missed by the time the property subscribes. If you access your Balance property between declaring it and adding an item, the property should be set.

Generally the approach for this is to ensure the observable will produce an initial value on subscription, for example:

JournalEntries.ItemsAdded.Select(_ => Unit.Default)
     .StartWith(Unit.Default)
     .Select(_ => JournalEntries.Sum(x => x.CreditAmount - x.DebitAmount))
     .ToProperty(this, x => x.Balance, out _balance);

Upvotes: 2

Related Questions