Stuart
Stuart

Reputation: 65

Observe for ItemChanged on two ReactiveLists

I have a ViewModel in which I would like to listen for changes to items in two ReactiveLists, Payments and AccountPayments. The Lists are instantiated and the ChangeTrackingEnabled is set to true:

this.Payments = new ReactiveList<transaction.PaymentViewModel>();
this.Payments.ChangeTrackingEnabled = true;`
this.AccountPayments = new ReactiveList<AccountPaymentViewModel>();
this.AccountPayments.ChangeTrackingEnabled = true;`

Then, defined in my ViewModel, I have an ObservableAsPropertyHelper readonly property:

readonly ObservableAsPropertyHelper<decimal> _totalPayments;
public decimal TotalPayments { get { return _totalPayments.Value; } }

My intent is to set TotalPayments whenever any of these items change in both lists. I tried using WhenAny:

this.WhenAny(vm => vm.Payments.ItemChanged,
            vm => vm.AccountPayments.ItemChanged,
            (a, b) => a.Sender.Payments
                .Where(x => x.Amount.HasValue).Sum(x => x.Amount.Value)
                + b.Sender.AccountPayments
                .Where(x => x.Amount.HasValue).Sum(x => x.Amount.Value))
            .ToProperty(this, vm => vm.TotalPayments, out _totalPayments);

While this compiles fine, it doesn't seem to catch the changes. I also tried using WhenAnyObservable:

this.WhenAnyObservable(
            vm => vm.Payments.ItemChanged,
            vm => vm.AccountPayments.ItemChanged)
            .Select(_ =>
                this.Payments.Where(x => x.Amount.HasValue)
                    .Sum(x => x.Amount.Value)
                + this.AccountPayments.Where(x => x.Amount.HasValue)
                    .Sum(x => x.Amount.Value))
            .ToProperty(this, vm => vm.TotalPayments, out _totalPayments);

But this won't compile. Is there a way to accomplish what I am trying to do? Any help would be greatly appreciated.

Upvotes: 3

Views: 768

Answers (1)

Charles Mager
Charles Mager

Reputation: 26213

The first won't work as it's observing property changes and ItemChanged itself won't change, it's an observable.

The second is pretty much correct, but requires a bit of a modification. WhenAnyObservable requires that all the observables are the same type. As you're uninterested in the actual result, you can select Unit and merge the two:

this.WhenAnyObservable(a => a.Payments.ItemChanged).Select(_ => Unit.Default)
    .Merge(this.WhenAnyObservable(a => a.AccountPayments.ItemChanged).Select(_ => Unit.Default));

You can't select Unit.Default within WhenAnyObservable as it re-writes this expression to observe the property changes to make sure it has the latest observable. If neither Payments nor AccountPayments will change (i.e. they're read only), you can omit the WhenAnyObservable altogether:

Payments.ItemChanged.Select(_ => Unit.Default)
    .Merge(AccountPayments.ItemChanged.Select(_ => Unit.Default));

Upvotes: 3

Related Questions