WPF page navigation like in MVC part 2: The MVVMC Framework

In my last post. I talked about navigation techniques in MVVM and how I didn’t like them too much. I also talked about learning Asp.NET Core is and how good the navigation / routing system is in there.

So, following the pain, I decided to create a lightweight navigation WPF framework similar to the one in Asp.NET Core. We’re still using MVVM, but adding controllers which makes it MVVMC, Model-View-ViewModel-Controller (This is how the library is called as well).

The code is available on GitHub.

Update 21/6/2018: I updated some features in the framework, added a NuGet package and added a thorough documentation on GitHub.

The following article is about using the navigation framework and how it implements the principles of MVVMC.

Getting started

To start with the MVVMC framework, simply install the NuGet Wpf.MVVMC to your WPF app.

Adding a Region

A Region is a Control with dynamic content. This is the part whose content you want changing when navigating. In my MainWindow:

The bottom of my window is the Region. This part is dynamic. The content of the Region can be changed and defined by a Controller (MainOperationController). A Controller controls only one Region and a Region is controlled by only one Controller.

The top part of the window, with two buttons is static and never changes.

File structure

A Controller and the Views & ViewModels connected to it should be in one namespace. You might want to have a separate folder for each Controller, like this:

Views

A view should be a FrameworkElement. So any User Control or a Custom Control will work. No need to derive from anything.

The only rule is that the name of the view should end with “View”.

A View and ViewModel pair is called a Page. So “AboutView” and “AboutViewModel” together make the page “About”.

ViewModels

A ViewModel should derive from MVVMCViewModel. Like this:

Another option is to derive from MVVMCViewModel<TController>. Like this:

Controllers

Here’s the MainOperationController example:

  • A controller class should be called [ControllerID]Controller
  • A Controller should derive from MVVMC.Controller abstract class.
  • A Controller is connected to a single Region. When this Region is loaded, the controller is created and navigation to Initial is requested. Each controller should implement InitialI() method.
  • Each navigation request invokes a Method with the same name in the controller. So when navigation to “About”   controller.Navigate(“About”, parameter: null);
    The “About()” method will be invoked.
    “About” is called the Action.
  • Optionally a navigation method can accept an object as a parameter.
  • When calling “ExecuteNavigation” from a method, the controller will create a View and ViewModel with the same name as the method.

    This code will:
    1) look for AboutView and AboutViewModel in the same namespace as the controller
    2) Create instances of them
    3) Set View.DataContext = ViewModel
    4) Change the Content of the relevant Region to be the View

Navigation options

From View:

You can use a special type of Command called NavigationCommand. Like this:

Pressing on About will find a controller called “MainApp.Pages.MainOperation.MainOperationController” and invoke the method About().

As you see, the Home Command doesn’t have an Action property set. This will bring us to Initial action.

From ViewModel:

Each ViewModel derives from MVVMCViewModel base class which exposes several methods for navigation:

  • GetController() will return the current control the ViewModel is related to. For example:
  • NavigationService is a singleton and you can use it from each ViewModel:

    Using NavigationService this way is available from anywhere in the application.

Navigating with parameter

All navigation methods allow to pass a parameter of type object. Here’s an example:
In ViewModel:

In Controller:

 

ViewBag

A controller can populate the navigation target ViewModel with data in 2 ways: A parameter and a ViewBag. The ViewModel base MVVMCViewModel holds them as properties:

We can use the “NavigationParameter” and the “ViewBag” in Initialize() method. Or, there’s a special kind of binding available ViewBagBinding which automatically binds to the ViewBag. But it’s a simple “OneTime” binding (for now).
In View:

 

Regions inside Regions

We might have hundreds of screens in our App and we might want different controllers to control these screen. For example we can have a “main” controller and a controller for a “mini-flow”. This can be achieved by adding another Region in a View. In the sample application we have a “MainOperationController” and one of the views introduces another Region which is controlled by a different Controller:

AllEmployeesView in MainOperation:

The View contains another Region. When loaded, AllEmployeesController will be called with Initial()

Since Initial calls SelectEmployee(), the Region’s content will become “SelectEmployeeView”

This finishes the technical overview. If you are curious, download the sample app from GitHub and run it. I’d love to hear your thoughts.

What more is missing?

There are still some important navigation features missing. Some are:

  • GoBack and GoForward navigation.
  • CanNavigate and CanNavigateBack functionality.
  • Better support for Testability – Have everything work with interfacs and dependency injection.

If there’s interest in this project I promise to add the missing functionality!

Is the MVVMC design pattern already being used?

I found out MVVMC (the design pattern, not my project) is already out there and some development teams are adopting it – Check out this blog post for example MVVM is dead, long live MVVMC!. I couldn’t find any WPF frameworks, so everyone who uses it probably wrote their own custom code. However, I did find a WinRT framework for MVVMC – ControllerRT.

ControllerRT is available on GitHubI didn’t run it but I did look over the code. It looks good and somewhat similar to what I did. But also with many differences. For example there’s one controller for each View and ViewModel.

Summary

We saw how we can use a lightweight MVVMC framework for navigation in a WPF project. This provides a nice abstraction. Now, the View and ViewModel of a specific screen aren’t responsible for the navigation logic to a different screen.

I’ll use this in my future WPF projects, and hope some of you will try it as well. If you do try it, I’d love to hear feedback at [email protected] or by comments in this post.

I’d like to thank Aleksey Kravetz for sitting with me on the project and helping me with some of the concepts of this project!

Share:

Enjoy the blog? I would love you to subscribe! Performance Optimizations in C#: 10 Best Practices (exclusive article)

12 thoughts on “WPF page navigation like in MVC part 2: The MVVMC Framework”

  1. Awesome article, been viewing different options for this problem, and MVVMC seems to be a strong choice.

  2. Peter Schmidl

    Hi!

    Great job! I’m wondering if there are other more common used frameworks based on MVVMC? Many MVVM stuff around related to WPF but not MVVMC!

    So thank you very much for your contribution!

    Greets Peter

  3. Fantastic job!
    I like the freedom of not being tied to a “head controller” to allow for completely free navigation, yet on the other hand giving the option of having a “main controller” if so desired. I especially like how with MVVMC, there’s even more component decoupling and SoC. One could work on navigation while another worked on ViewModel – View interaction and so on.

    I would very much like to see continued work on this project, particularly the “missing features” you mentioned.

    Keep up the good work!

    1. Thanks Garrett, much appreciated!

      Unfortunately, besides some great feedbacks, I don’t see developers adopting this framework.
      I’ll definitely add features the next time I’ll start a new WPF app and need them myself.
      Same if someone starts using the project and has some issues.

      For now though, it seems pointless to add more functionality if no-one is using it.

      Although it’s possible there’s no adoption due to lack of activity, it’s also very likely that even if I put in lots of effort, it won’t help anyone.

      Michael

  4. “Unfortunately, besides some great feedbacks, I don’t see developers adopting this framework.”

    Well, there are some (popular) MVVM frameworks with ViewModel-first navigation, like ReactiveUI.

    1. Sure, ReactiveUI looks interesting.
      I didn’t mean all WPF navigation frameworks aren’t be popular, just that this specific project isn’t getting much traffic on GitHub.
      Hope this changes with the better documentation and my new additions.

    1. By showing modal views I suppose you mean showing an “overlaying” view, while the previous view remains “in the back”. So like a dialog.
      The regular navigation will always Unload the previous View and Load the new view, and there’s no API to show modal view.

      However, you can rather easily implement modal views with 2 controllers. For example, in the outer view (or Window) write:

      The “Modal” controller will show an empty view by default, so only the “Regular” region will be seen. When you want to display a modal view, navigate with the “Modal” view, effectively covering the Regular view and acting like a modal view.

Comments are closed.