We're using the MVP design pattern here, and we've gone with the presenter-per-UserControl style.
This answer suggests two different styles of presenter construction:
Each presenter instantiates any child presenters that it has.
A controller class instantiates all the presenters and handles communication between them.
Unfortunately there's no mention of how and where the view is wired up. In another project I'm using the factory pattern to create my presenters and pass them views using dependency injection. The views are created in a view factory that instantiates the views with their appropriate UserControls which are then added to the form with Controls.Add.
From what I gather from the first link, the Visual Studio designer is used to add the UserControls - which is fine, but then it seems that the presenters would be unnecessarily coupled to the view layer.
So how should I add my subviews and wire up the View-Presenter pair?
The way I tend to do this is I put a placeholder in the "master" view for the sub views, I normally use a panel control.
I always wire up my MVP so that the Presenter creates the view. Never the other way round (I hate that style) The presenter then exposes a GetView() method that returns the view.
The master presenter can then create a sub presenter get its view and tell the master view to render it. This is done through a method on the masterview that adds the sub view to the controls collection of the panel control.
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.
As far as i understand ViewModel communicates with View via databinding. But how can one create in ViewModel UIElements for View.
Thanks.
The ViewModel should not create any UIElements directly because the ViewModel should not depend on the View. The ViewModel provides data that the View (i.e. the UIElements) can bind against.
If your question is geared toward how to bootstrap a View, there are two approaches: View-first and ViewModel-first. In the former you create the View first and then create and bind against the ViewModel. In the latter you make the ViewModel create the View (through interfaces). Read more about it here.
If your question is geared toward composing the view of UIElements, this is done through DataBinding and the use of DataTemplates and ControlTemplates.
MVVM is a loose design pattern, it is accectable to put code in the code behind as long as it purely concerned with the UI only, just keep in mind that it may be harder to unit test.
And strictly speaking the ViewModel does not communicate to the View, there is no reference to the View in the ViewModel, rather the View reads data from the ViewModel and executes commands on the ViewModel.
The problem is dynamic component creation needs as I see.
You can put a Container object on a view then on modelView create UIElements and Bind this UIElement collection to Container's Content Property. But I think its not a good practice. This approach breaks Model and View seperation.So you need to avoid of dynamic component creation.
MVVM approach is a bit diffrent. Sometimes force us using tricks. i.e. Instead of using ListBox's MemberPath property you define a ItemTemplate and put ButtonBase elements on the template for supporting Commanding! Or you Extend ListBox and Support Commanding.
My offer instead of dynamic object creation. Use DataTemplates and change the binded members on ModelView,then the view will be automatically created for you.For complex senario's it could be hard. We do them all for the sake of keeping MVVM structure.
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 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