MVVM Application – Who Should Control Navigation?

design-patternsmvvmsilverlight

Example #1: I have a view displayed in my MVVM application (let's use Silverlight for the purposes of the discussion) and I click on a button that should take me to a new page.

Example #2: That same view has another button that, when clicked, should open up a details view in a child window (dialog).

We know that there will be Command objects exposed by our ViewModel bound to the buttons with methods that respond to the user's click. But, what then? How do we complete the action? Even if we use a so-called NavigationService, what are we telling it?

To be more specific, in a traditional View-first model (like URL-based navigation schemes such as on the web or the SL built-in navigation framework) the Command objects would have to know what View to display next. That seems to cross the line when it comes to the separation of concerns promoted by the pattern.

On the other hand, if the button wasn't wired to a Command object and behaved like a hyperlink, the navigation rules could be defined in the markup. But do we want the Views to control application flow and isn't navigation just another type of business logic? (I can say yes in some cases and no in others.)

To me, the utopian implementation of the MVVM pattern (and I've heard others profess this) would be to have the ViewModel wired in such a way that the application can run headless (i.e. no Views). This provides the most surface area for code-based testing and makes the Views a true skin on the application. And my ViewModel shouldn't care if it displayed in the main window, a floating panel or a child window, should it?

According to this apprach, it is up to some other mechanism at runtime to 'bind' what View should be displayed for each ViewModel. But what if we want to share a View with multiple ViewModels or vice versa?

So given the need to manage the View-ViewModel relationship so we know what to display when along with the need to navigate between views, including displaying child windows / dialogs, how do we truly accomplish this in the MVVM pattern?

Best Answer

Navigation should always be handled in the ViewModel.

You're on the right track with thinking that the perfect implementation of the MVVM design pattern would mean you could run your application entirely without Views, and you can't do that if your Views control your Navigation.

I usually have an ApplicationViewModel, or ShellViewModel, which handles the overall state of my application. This includes the CurrentPage (which is a ViewModel) and the code for handling ChangePageEvents. (It's often also used for other application-wide objects such as the CurrentUser, or ErrorMessages too)

So if any ViewModel, anywhere, broadcasts a ChangePageEvent(new SomePageViewModel), the ShellViewModel will pickup that message and switch the CurrentPage to whatever page was specified in the message.

I actually wrote a blog post about Navigation with MVVM if you're interested