Search code examples
wpfmvvmsystem.reactivemaster-detailreactiveui

Master-details using ReactiveUI via WhenAnyValue doesn't work for me


I am implementing a typical master-details GUI pattern using WPF and ReactiveUI. I would like to keep the master viewmodel and the details viewmodel decoupled from each other without resorting to something more fragile and indirect like message bus. However something isn't working.

I have two questions:

  1. Why is WhenAnyValue not working in my code below?
  2. What is the recommended way of implementing decoupled master-details in ReactiveUI nowadays?

Code:

public class ShellViewModel : ReactiveObject
{
    public ShellViewModel(OrderListViewModel orderListViewModel, OrderDetailsViewModel orderDetailsViewModel)
    {
        OrderListViewModel = orderListViewModel;
        OrderDetailsViewModel = orderDetailsViewModel;

        this.WhenAnyValue(x => x.OrderListViewModel.SelectedOrderHeader).Do(h =>
        {
            OrderDetailsViewModel.Set(h);
        });
    }

    public OrderListViewModel OrderListViewModel { get; }
    public OrderDetailsViewModel OrderDetailsViewModel { get; }
}

I have omitted the two underlying viewmodels and related views because they are very typical (observable list + selected item property) and seem to be working fine by themselves.

Update: the the #1 can be "fixed" by using Subscribe instead of Do. I don't know what is the purpose of the latter?


Solution

  • Why is WhenAnyValue not working in my code below?

    Because Rx observables (like the one returned from your WhenAnyValue) are lazy by nature. That means, nothing is going to happen until you call Subscribe on them. As you stated...

    the the #1 can be "fixed" by using Subscribe instead of Do. I don't know what is the purpose of the latter?

    Its' purpose is to introduce side effects to your Rx stream. For example, you could inject some logging into this method.

    this.WhenAnyValue(x => x.OrderListViewModel.SelectedOrderHeader)
        .Do(_ => Console.WriteLine("Order selected!")
        .Subscribe(h => OrderDetailsViewModel = h);
    

    Note that introducing side effects in Rx should generally be avoided.

    What is the recommended way of implementing decoupled master-details in ReactiveUI nowadays?

    Your code looks fine to me. Alternative approach which comes to my mind is exposing IObservable<OrderDetailsViewModel> directly from the OrderListViewModel.

    Oh, and apart from that, you should definitely consider feeding these view models to ObservableAsPropertyHelper in your ShellViewModel class.