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?
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
Related
I want to get a reference from a user control view model to the window that holds the user control. How can I do this?
If I can get a reference to the view from view model then I can use:
Window parentWindow = Window.GetWindow(userControlReference);
So my questions are:
What's the best way to get the reference from user control view model to the window that holds the user control?
If I want to use the above code, what is the best way to get a reference to view from view model in Caliburn Micro?
A viewmodel will generally inherit from IViewAware assuming that it's an IScreen implementation
You can just cast a Screen to IViewAware and use the GetView() method to get a reference to the view. I think you can implement IViewAware on your own viewmodels and Caliburn will automatically raise the ViewAttached event so you can keep a reference to the view but I might have a look at the docs
Bottom line: check out the IViewAware interface
Edit:
From the docs...
IViewAware – Implemented by classes which need to be made aware of the view that they are bound to. It has an AttachView method which is called by the framework when it binds the view to the instance. It has a GetView method which the framework calls before creating a view for the instance. This enables caching of complex views or even complex view resolution logic. Finally, it has an event which should be raised when a view is attached to the instance called ViewAttached.
I am new to MVVM and now doing some MVVM refactorying work on a silverlight project, suppose it is a book shopping application.
The View is a book list, I bind the title of the books to the ViewModel. So I have a public string Title { get; set; } in ViewModel, also a public string Title { get; set; } in Model (am I right?)
Now I want put a event handler to update the book title, should I put the event handler in ViewModel or Model? and what is the Model used for?
In my opinion "Neither"... Add controller classes to the mix of MVVM instead.
The problem with putting controller code in view models is that is makes them harder to test independantly. In many ways I see this as just as bad as code behind.
It seems to me that everyone assumes MVVM has no controllers as they left out the C. MVVM is really a variation of MVC "that just adds ViewModels".
Maybe it should have been called MVCVM instead?
ViewModels are only there to offload the "GUI" code from the view and to contain any data for binding. ViewModels should not do any processing. A good test is that your ViewModel is testable via automated unit tests and has no dependencies on data sources etc. They should have no idea where the data is actually coming from (or who is displaying it).
Although it can be overlooked/avoided, a Controller should be responsible for deciding what data model to display and in which views. The ViewModel is a bridge between Models (the M in MVVM) and Views. This allows simpler "separated" XAML authoring.
The pattern we are using successfully on all recent projects is to register controllers only, in modules, and initialise them at startup. The controllers are very light/slim and the only thing that needs to hang around for the life of the app listening for, or sending, messages. In their initialise methods they then register anything they need to own (views and viewmodels etc). This lightweight logic-only-in-memory pattern makes for slimmer apps too (e.g. better for WP7).
The basic rules we follow are:
Controllers make decisions based on events
Controllers fetch data and place it in appropriate View Model properties
Controllers set ICommand properties of View Models to intercept
events
Controllers make views appear (if not implied elsewhere)
View Models are "dumb". They hold data for binding and nothing else
Views know they display a certain shape of data, but have no idea
where it comes from
The last two points are the ones you should never break or separation of concerns goes out the window.
In simplest terms, the Model is the 'real' underlying data model - containing all the info for the booklist that might be needed by the application, able to get and set data from your database.
The ViewModel is an object that exists primarily to provide data binding for your View. It might be a subset of the Model, or it might combine properties from multiple Models into a single object. It should contain the necessary and sufficient properties to allow the View to do its job.
If the event handler relates to the View, then it belongs in the ViewModel. You might try using the Command Pattern (see Custom WPF command pattern example) if it fits your purpose.
Currently I'm building an application using latest Prism for Silverlight 4.
I've a module and in that module I've two views with view models. Also I've a module view with two regions for each view.
In module initialization I'm registering my views and view models in Unity container and also register views with corresponding regions.
The problem is that views should display something similar to table-detail information - first view shows available entities ans the second view shows detail of selected entity.
I need a way how to pass them initial selected entity. Newly created first view doesn't have any selected entity and newly created second view doesn't show any details.
Currently I'm doing that this way:
In module I create two view models and register them as instances in Unity container and then I register views as types for corresponding regions. Each view subscribes to EntitySelectedEvent from EventAggregator. Module initializer publish this event after initialization and this way two views are selecting the same entity.
I know this looks ugly - I tried publishing this event from one of view models but the problems is that EventAggregator in Prism doesn't support durable subscribers - this means that if the second view model didn't subscribe to event before the first view model fired it, it won't receive and event. I know this is a normal behavior of EventAggregator, but I'm looking for a solution when view models can fire events without depending on initialization order of them - that is the first model can fire event before the second model was created and the second model will receive this 'queued' event after subscribing to it.
Are there any other messaging implementations for WPF/SL which do support such behavior or using a mediator (in my example it's a module itself) isn't such a bad idea after all? One big problem with mediator is that models must be created right away in initialize and they can't be registered as types in container because this leads again to missing subscribers.
Create a Model that will be shared by ViewModels of each of the views.
When a row gets selected in View 1 its ViewModel (via a CurrentEntity property bound to a selected row) will update the Model.
ViewModel of View 2 would subscribe to changes of Model's CurrentEntity and will properly update it's own CurrentEntity property that would cause it's View to update.
I am currently learning how to make advanced usage of WPF via the Prism (Composite WPF) project.
I watch many videos and examples and the demo application StockTraderRI makes me ask this question:
What is the exact role of each of the following part?
SomethingService: Ok, this is something to manage data
SomethingView: Ok, this is what's displayed
SomethingPresentationModel: Ok, this contains data and commands for the view to bind to (equivalent to a ViewModel).
SomethingPresenter: I don't really understand it's usage
SomethingController: Don't understand too
I saw that a Presenter and a Controller are not necessary but I would like to understand why they are here. Can someone tell me their role and when to use them?
I had exactly the same problem when I first went through Prism.
Controllers are basically for logic that spans an entire module, whereas Presenters are for logic that is specific to a View.
For example, a Presenter would respond to a command that results in a button in the view being disabled. A Controller would respond to a command that results in the View (and Presenter) being changed entirely, or perhaps loading a different View/Presenter in a different region in the module's shell.
Edit: As for when to use them, you can skip the Controller entirely if you have no need for the orchestration mentioned above. The simplest application will just have a:
Module: registers the view/presenter into the Region
Presenter: responds to commands from the view and modifies the ViewModel.
ViewModel: adapter between Presenter and View that implements INotifyPropertyChanged
View: binds to ViewModel and displays UI
Edit: As for Presenter vs ViewModel, most of your logic should be in your Presenter. Think of your ViewModel as housing the logic for your view, but the Presenter as dealing with the consequences of interacting with the view.
For example, the user clicks the "Search" button in your View. This triggers an ICommand, which is handled by your Presenter. The Presenter begins the search and sets the ViewModel.IsSearching property, which fires the PropertyChanged notification for CanSearch. CanSearch is a readonly property that is based on several other properties (eg. IsSearchEnabled && !IsSearching). The "Search" button in the View has its Enabled property bound to CanSearch.
In my opinion Controller in here refers to Application Controller
I am implementing MVP/M-V-VM in WPF and I'm having good luck with it so far. However, I don't see how this model supports implementing Modal dialog boxes. I've derived my work from Crack.NET (http://www.codeplex.com/cracknetproject) to learn how this stuff works.
I have a ShellView view (which is just XAML) that has a menu on it. The menu binds to a command in the ShellModelView that says "EditPreferences".
The ShellModelView implements the ICommand for EditPreferences and here we want to put up a dialog box to let the user edit preferences for the application.
Several problems here:
1. The ShellModelView doesn't have a reference to the ShellView to properly parent the dialog. The ShellModelView is the DataContext of the ShellView but I don't see a backreference that's setup.
2. The ShellModelView shouldn't be loading explicit UI anyway. So what's the proper interaction model here?
3. How do I build up my PreferencesDialog so that it's properly separated between logic and view as well? PreferencesDialog itself needs to be a Window so you can call ShowDialog on it, but that means you need a reference to the Window (e.g. View) in order to instantiate it. Ideally I should be able to unit test the code/validation within PreferencesDialog without instantiating the view (using a Mock view perhaps?).
Perhaps this is not the appropriate way to look at it, but this is the approach I take with M-V-VM in WPF. Opening windows and dialog boxes or an "EditPreferences" view are UI specific functions. If I were to rewrite the your entire UI replacing all of the views, I may wind up combining the "EditPreferences" view with another view, and therefore never want to open it in another screen. If this were tied to the ViewModel, it would be difficult to get around. In this particular situation, I would have a button or menu item in my "ShellView" that creates a new instance of my "EditPreferences" view, and then passes in the "EditPreferences" ViewModel which may either come from a property in my "ShellViewModel", or perhaps my "EditPreferences" view instantiates the ViewModel itself.
Here is a similar question on SO that basically says the same thing: M-V-VM Design Question. Calling View from ViewModel
You will need a controller in your case. The controller should be in charge for showing the preference dialog window.
As I can envision it the controller should be responsible for creating the ShellModelView and binding view's DataContext to it. The controller should be also responsible for handling command execution of EditPreferences. In the execution logic the controller will create a new PreferencesDialog and its corresponding view model.
You can find similar patterns in Prism if you haven't already did it. You can also reuse the DelegateCommand provided there :)
Have the PreferencesDialog implement a interface that is one of the properties of the EditPreference command. The command would interact with the dialog through the interface. For Unit Testing the mock object would implement the interface instead.
The dialog class then can reside on your highest layer.
My 2 cents is:
Pass some kind of viewfactory contract as the command parameter or inject a viewfactory contract into the view model. The view model will them use the viewfactory to create any modal/non modal views it needs. The viewfactory could also take in as a parameter of its Show/ShowModal method a viewmodel to display. Furthermore, the viewfactory could use a datatemplate to display any viewmodal passed in as a parameter.
Add a ShowViewModel property to the viewmodel in question. A DataTrigger could then watch for this property and when it is of a particular type show the view, etc.