Orestis P.
Orestis P.

Reputation: 825

Nested Controllers using MVVMC pattern

I've started using MVVMC (otherwise known as MVCVM or MVVM+), which takes the MVVM pattern and adds a controller between the view, the view model and the model. The controller is responsible for calling the application API to retrieve the models which it then converts into view models which are then bound to its associated view. This way, the ViewModel remains with a single responsibility; to provide data to the view. However, I encountered a few problems with this approach.

I have a MainWindowViewModel which provides data to the MainWindowView. A MainWindowController was also created which drives this interaction. The problem is that the MainWindowView contains many other views within (e.g. multiple instances of ItemsListView) and those views contain more views within them.

Initially, I added all the required view models into the MainWindowViewModel so that each sub-view can bind to a property of its parent's view model. Essentially all the view data of the main window are held in a single instance of this view model. With this approach, I will need multiple controllers to drive all these interactions. Each one should also instantiate the view models based on its own logic. Does this mean that the MainController should instantiate and keep reference to all the other controllers, which it will use to populate the inner view models of the main view model? Wouldn't that make the controller too crowded?

Another approach is to use a single controller for all views within a window but it seems that this will violate the single responsibility principle.

What is the correct way to implement controllers in the MVVMC pattern in WPF?

Upvotes: 3

Views: 1278

Answers (1)

Michael_S_
Michael_S_

Reputation: 528

I assume all of these inner views are dynamic since you used the word "interaction". So I think it's best for you to have different Controllers for each of those views.

I recently developed a WPF MVVMC framework. I'll tell you how I deal with your type of problem in the framework.

In the view MainWindow.xaml:

<Window>
 <mvmmc:Region ControllerID="View1"/><!-- View 1 -->
 <mvmmc:Region ControllerID="View2"/><!-- View 2 -->
 <mvmmc:Region ControllerID="View3"/><!-- View 3 -->
</Window>

Region is a special Control that has dynamic content, controlled by a Controller. When loaded, a controller instance is created according to ControllerID and the controller will make sure to create a View and ViewModel as the Region's content.

Now, suppose in MainWindowViewModel, you want to change content of View1 and View2. The code is:

void ChangeContentOfView1AndView2()
{
  _navigationService.GetController("View1").Navigate("SomeAction");
  //Here's another way to find a controller and navigate
  _navigationService.GetController<View2Controller>.OtherAction();
}

So the MainWindowViewModel can find a controller which controls a certain Region in your code and ask it to navigate. The logic for navigation, like populating the specific ViewModel falls to the specific controller. Not to MainWindowViewModel.

In this simple solution, there isn't MainWindowCotroller since MainWindow's view is static. No need for controller. The ViewModel, according to button press or whatever event, finds the relevant Controller of the Region and invokes it.

In View1Controller:

public class View1Controller : Controller
{
  public void SomeAction()
  {
    ExecuteNavigation();
  }
}

ExecuteNavigation will find a Control called "SomeActionView" and a ViewModel called "SomeActionViewModel" and will set the relevant Region's content as SomeActionView. With its DataContext to be SomeActionViewModel.


Check out the MVVMC framework I use here if you're looking for a complete WPF solution. The navigation somewhat resembles Asp.NET Core.

Blog post with documentation: http://michaelscodingspot.com/2017/02/15/wpf-page-navigation-like-mvc-part-2-mvvmc-framework/

GitHub: https://github.com/michaelscodingspot/WPF_MVVMC

Upvotes: 2

Related Questions