Reactiveui: [WPF] Complex and nested Views and ViewModels. Best Practices?

Created on 19 Apr 2016  路  4Comments  路  Source: reactiveui/ReactiveUI

I am really new to ReactiveUI but what I've seen so far impressed me and I'd like to use ReactiveUI more and more in my projects. Unfortunately, the lack of documentation is somehow irritating for starters like me.

Context
I have a ShellView (which is a Window), a TitleBar (ViewModelViewHost), a Content (RoutedViewHost) and a StatusBar (ViewModelViewHost).
Now in my ShellViewModel there are of course the properties which are connected to the View.

I've made it like the example of @kondaskondas in the repository FirstStepsRUI.

In the TitleBar is a Menu to switch between ViewModels. The method Router.Navigate.Execute(...) is invoked in the ShellViewModel.

Problem
If I want to navigate to another ViewModel, I have to create a new ViewModel object with all required parameters which means that my ShellViewModel needs a constructor with _ALL_ required parameters my sub viewmodels need. For example, my FirstViewModel needs 3 different arguments, my SecondViewModel needs other 2 arguments and my ThirdViewModel needs another 4 arguments. To instantiate and navigate to these ViewModels inside my ShellViewModel, I have to pass 9 arguments to my ShellViewModel.

Is this best practice or are there simpler solutions? Calling the service locator inside of a ViewModel isn't really best practice because of testing, isn't it?

I've also tried MVVMCross where you can call ShowViewModel<T>() inside of other ViewModels without specifying arguments. Is there something like Navigate.Execute<T>() which I have missed? :see_no_evil:

Hope it is understandable. :relaxed:

outdated

Most helpful comment

I wanted to include something else that isn't always immediately apparent to RxUI beginners. The ViewModelViewHost is only necessary if you plan on switching out the _type_ of the VM and therefore the type of the _view_ that is attached to the visual tree. So for example, your StatusBarView likely only ever displays a StatusBarViewModel (and only one at that!), so you don't need the additional overhead and complexity of managing that view through a VMVH.

All 4 comments

Technically, composition/dependency resolution is not really anything RxUI is itself opinionated about. Depending on who you ask in the RxUI community, you will certainly get different answers.

A common approach is to have your VMs take arguments with defaults, and resolve from the service locator if no value is provided:

C# public SomeViewModel(ISomeService someService = null) { someService = someService ?? Locator.Current.Resolve<ISomeService>(); }

This facilitates testing because you can pass a specific ISomeService from your unit test. Of course, your tests would need to either pass all dependencies, or configure the service locator with some defaults.

Another approach is to separate the responsibility of composition out into a separate class (commonly called CompositionRoot). Mark Seemann has a great blog post about this here. I use this technique in my Workout Wotch application, for example.

Key to using the composition approach is that if a VM needs to create another VM, you inject a factory. The factory only takes the arguments that cannot be resolved by the container itself.

You could also use a full-blown off-the-shelf DI container, but I have found composition root to be better in all possible ways.

HTH

Thank you for your detailed answer, this helped me a lot!

I wanted to include something else that isn't always immediately apparent to RxUI beginners. The ViewModelViewHost is only necessary if you plan on switching out the _type_ of the VM and therefore the type of the _view_ that is attached to the visual tree. So for example, your StatusBarView likely only ever displays a StatusBarViewModel (and only one at that!), so you don't need the additional overhead and complexity of managing that view through a VMVH.

Thanks, that sounds legit. 馃憤

Was this page helpful?
0 / 5 - 0 ratings