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:
WhenAnyValue
not working in my code below?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?
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.