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
Related
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
I'm trying to get to grips with different patterns (MVP, MVVM etc) and find one that suits my needs. After all my reading I'm still not sure. Hopefully someone can shed some light on this for me.
At the moment I have a WPF View which implements an interface ICustomView. This interface is injected into my Presenter. The presenter then is responsible for subscribing to data, managing subscriptions etc. When the data is returned to the Presenter it calls various methods against the Model (an IObservable collection of CustomBusinessObjects). It does this using the interface ICustomView since the IObservable is a property of the Model.
The problem I see with this is the Model is too coupled with the View. Also the Presenter is deciding which methods to call against the Model. At the moment the View consists of a WinForms grid and this is exposed by the ICustomView allowing the Presenter to call methods against the View. However it adds to the coupling of Presenter and View which makes it difficult to swap out this WinForms grid for a WPF grid or chart etc
I am considering making the Model an entirely seperate entity lets say IModel with a single method ProcessUpdate(string topic, IMessage payload). This would move logic away from the presenter into the Model. It would also mean more than one view could share the same model. The custom model could have additional interfaces for specific customisations but the Presenter would only need to know about IModel.
Does this sound like a reasonable idea? Am I missing something here?
Any advice appreciated.
Thanks
I would recommend switching from MVP to MVVM because you are using WPF. I would only use MVP if you were using ASP.Net or WinForms.
That being said, your MVVM objects would be:
Model: Simple data object. It should not contain any functionality such as Save or Edit, but can have Validation logic.
View: Your UI. I usually do mine as a DataTemplate for the ViewModel class type. It should bind to your ViewModel's Properties and Commands.
ViewModel: The piece that combines the two. Any data displayed in the View should bind to a property in the ViewModel. Any commands in your View such as Button Clicks should also point to methods in the ViewModel.
For example, when a user hits a GetCustomer button on the View, the ViewModel should receive the command, go and get the CustomerModel, and expose it's Properties for the View to bind to. When the user hits Save the ViewModel should validate that the Model is valid, and then execute the Save code using its CustomerModel property.
Personally, when using WPF I prefer to use a WPF datagrid, and bind it to a datacontext in the MVVM pattern. I think the first thing you need to get rid of is the WinForms grid (it will be almost impossible to decouple your model/view as long as you are using a WinForms grid.
I would do research on a few different things.
The MVVM pattern
WPF DataGrid
Binding the DataGrid to a DataContext
Once you get to that point, all you will need to do is update your datacontext, and your view will update with it.
In the MVVM (Model-View-ViewModel) pattern should the ViewModel reference the view. I would think that it should not. But how should the following scenario be handeled? I have a view that has a tab control as the main container, the viewmodel for this view implements a command to add a new tab to the tab control. The easy way would be to allow the viewmodel to reference the view and then in the command implementation to just programmatically add the new tab to the tabcontrol in the view. This just seems wrong. Should I somehow bind the tabcontrol to the viewmodel and then implement a data/control-template to add the new tabs. I hope this makes some kind of sense to somebody :)
In "pure" MVVM, the ViewModel shouldn't really reference the View. It's often convenient, however, to provide some form of interface in the View whereby the ViewModel can interact with it.
However, I've found that I almost never do that anymore. The alternative approach is to use some form of attached property or blend behavior within your View, and bind it to your ViewModel properties. This allows you to keep the View logic 100% within the View. In addition, by creating a behavior for this, you create a reusable type that can be used to handle this in every ViewModel->View interaction. I strongly prefer this approach over having any View logic within the ViewModel.
In order to demonstrate this technique, I wrote a sample for the Expression Code Gallery called WindowCloseBehavior. It demonstrates how you can use a Behavior within the View bound to properties in the ViewModel to handle controlling a Window's life-cycle, including preventing it from being closed, etc.
Reed and Dan covered the general approach but in reference to your specific case, TabControl is an ItemsControl and so can bind its ItemsSource to a data collection in your ViewModel representing the set of tabs to display. The UI for each type of tab can then be represented by a DataTemplate specific to the data type of an item (either using DataType or a DataTemplateSelector). You can then add or remove data items as needed from your VM and have the tabs update automatically without the VM knowing anything about the TabControl.
I find that it's often a helpful compromise to expose an interface on the View that handles View-specific functionality. This is a good way to handle things that are awkward to accomplish with pure binding, such as instructing the form to close, opening a file dialog (though this often gets put in its own service interface) or interacting with controls not designed well for data binding (such as the example you provided.)
Using an interface still keeps the View and ViewModel largely decoupled and enables you to mock the specific IView during testing.
One of us is missing something obvious. Your tab control is an ItemsControl. You should bind the ItemsSource of your tab control to an ovservable collection in your view model. When you handle the command in your view model to add a tab, you simply add a new element to this collection and, voila, you've added a new tab to the control.
I have an application that need to open a dialog from a button where the user enters some information.
At the moment I do it like this (which works fine)
The button click generates a command in the ViewModel.
The ViewModel raises an event which the Controller listens to.
The Controller works out the details of the new window (i.e. View, ViewModel & model) and opens it (ShowDialog)
When the window is closed the Controller adds the result to the eventargs and returns to the ViewModel
The ViewModel passes the information to the Model.
There are a lot of steps but they all make sense and there is not much typing.
The code looks like this (the window asks for the user's name)
ViewModel:
AskUserNameCommand = DelegateCommand(AskUserNameExecute);
...
public event EventHandler<AskUserEventArgs> AskUserName;
void AskUserNameExecute(object arg) {
var e = new AskUserNameEventArgs();
AskUserName(this, e);
mModel.SetUserName(e.UserName);
}
Controller:
mViewModel.AskUserName += (sender,e) => {
var view = container.Resolve<IAskUserNameView>();
var model = container.Resolve<IAskUserNameModel>();
var viewmodel = container.Resolve<IAskUserNameViewModel>(view, model);
if (dlg.ShowDialog() ?? false)
e.UserName = model.UserName;
}
My question is how the horizontal communication works in the MVVM pattern.
Somehow it seems wrong to let the controller be involved in the data transfer between the models.
I have looked at the mediator pattern to let the models communicate directly. Don't like that idea since it makes the model depending on implemetations details of the GUI. (i.e. if the dialog is replaced with a textbox, the model need to change)
I don't like most of the current suggestions for one reason or another, so I thought I would link to a nearly identical question with answers I do like:
Open File Dialog MVVM
Specifically the answer by Cameron MacFarland is exactly what I do. A service provided via an interface to provide IO and/or user interaction is the way to go here, for the following reasons:
It is testable
It abstracts away the implementation of any dialogs so that your strategy for handling these types of things can be changed without affecting constituent code
Does not rely on any communication patterns. A lot of suggestions you see out there rely on a mediator, like the Event Aggregator. These solutions rely on implementing two-way communication with partners on the other side of the mediator, which is both hard to implement and a very loose contract.
ViewModels remain autonomous. I, like you, don't feel right given communication between the controller and the ViewModel. The ViewModel should remain autonomous if for no other reason that this eases testability.
Hope this helps.
i use this approach for dialogs with mvvm.
all i have do do now is call the following from my viewmodel to work with a dialog.
var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);
I have come across similar problems. Here is how I have solved them, and why I have done what I have done.
My solution:
My MainWindowViewModel has a property of type ModalViewModelBase called Modal.
If my code needs a certain view to be modal, it puts a reference to it in this property. The MainWindowView watches this property through the INotifyPropertyChanged mechanism. If Modal is set to some VM, the MainWindowView class will take the VM and put it in a ModalView window where the appropriate UserControl will be shown through the magic of DataTemplates, the window is shown using ShowDialog. ModalViewModelBase has a property for DialogResult and a property called IsFinished. When IsFinished is set to true by the modal VM, the view closes.
I also have some special tricks for doing interactive things like this from backgroundworker threads that want to ask the user for input.
My reasoning:
The principle of modal views is that other views are disabled, while the modal is shown. This is a part of the logic of the View that is essentially lookless. That's why I have a property for it in the MainWindowViewModel. It I were to take it further, I should make every other property or command for all other VM's in the Main VM throw exceptions, while in modal mode, but I feel this to be excessive.
The View mechanism of actually denying the user any other actions, does not have to be performed with a popup window and showdialog, it could be that you put the modal view in the existing window, but disable all others, or some other thing. This view-related logic belongs in the view itself. (That a typical designer can't code for this logic, seems a secondary concern. We all need help some times.)
So that's how I have done it. I offer it only as a suggestion, there is probably other ways of thinking about it, and I hope you get more replies too.
I've used EventAggregator from Prism v2 in similar scenarios. Good thing about prims is that, you don't have to use entire framework in your MVVM application. You can extract EventAggregator functionality and use it along with your current setup.
You might have a look at this MVVM article. It describes how a controller can communicate with the ViewModel:
http://waf.codeplex.com/wikipage?title=Model-View-ViewModel%20Pattern&ProjectName=waf
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.