I have implemented the MVP pattern (passive view) in my C# Forms application.
In my case the model is a motor controller laser system, where the model actually is like a facade of two other models (one the motor control system, the other the laser system).
My presenter is a mediator of model-events and methods to the view which handles the user interface.
Suppose my view has a setting for the laser power. The user sets this to some value, which gets sent to the presenter, which in turn send the request to the model.
If the laser power is out of range my model throws an error which get catched by my presenter.
How do I best mediate this message to the user?
I thought about making, in my view, a method; HandleError(string message), and invoke this from the presenter.
This is my first project using MVP, so I haven't got the experience to say which way is the best way.
In the view, create a property for an Error Message. From the presenter you can set the value of this property. Back in the view on the setter for the property, store the value that's set as any typical property would do, but in addition add your logic for whatever the user interface needs to do. The View can then control the flow of what happens within itself.
Related
I’m new to MVVM and am trying to establish good practices as I convert a large non-Model-View WinForms project. Here’s an example of a solution I’ve implemented. I’m wondering if there is a better pattern for solving this class of problem.
MyModel has ten properties. MyView exposes two of them for users to update. MyViewModel handles the usual stuff in between.
Other models depend on MyModel’s properties, so I only want to change MyModel when values are committed to. MyView has OK and Cancel buttons, so instead of having MyViewModel directly update MyModel when the user interacts with MyView, I’ve created another layer: MyTempModel. MyTempModel contains two properties which correspond to the two from MyModel.
So inside MyModel, prompting code looks something like this:
var tempModel = new TempModel{Prop1=Prop1,Prop2=Prop2};
bool? response = new MyView().ShowDialog();
if (response.HasValue && response.Value)
{
Prop1 = tempModel.Prop1
Prop2 = tempModel.Prop2
}
Thus if the user clicks ‘Cancel’, MyModel’s properties are not changed.
Note: Not shown here is that I set a reference to MyTempModel in MyViewModel once to establish that wiring. MyViewModel subscribes to property changed events in MyTempModel and MyView uses databinding to connect to MyViewModel.
model - > view data flow summary:
MyModel sets property in MyTempModel, which fires an event. MyViewModel’s evenhandler picks up the change and sets a dependency property, causing MyView to update.
view -> model data flow summary:
Changes to MyView result in dependency property in MyViewModel to change. This property’s setter pushes the value to MyTempModel. When user clicks Ok then MyModel copies values from MyTempModel.
I'm particularly interested in the role of the ViewModel. I have in mind that keeping dialogs "humble" is a good thing, and maybe that is spilling over into making ViewModels humble. So comments on what kind of functionality you put into your view models vs your domain models would be especially interesting.
I appreciate any and all design wisdom for this pattern. I'll gladly update this info if anyone needs clarification.
I don't think the use of a proxy class is a bad thing. I'm a little concerned about this: 'MyModel sets property in MyTempModel, which fires an event. MyViewModel’s evenhandler picks up the change and sets a dependency property, causing MyView to update.' I think that renders your Model classes a little less universal and obscures that functionality from the ViewModel. I would just use the ViewModel to mediate the swap in/out of the proxy, rather than having the Models do it. I also think that using a proxy opens up use of DataTemplates for that type which could make the UI work easier.
An alternative to the direction given by Alex is to make the viewmodel a representation of what is in both client and server side.
E.g., the number shown is always what the user entered and the background of the number indicates that this number has been confirmed or not (pending)by the server. The viewmodel could use two different properties to contain these values and a status property to indicate the fact the property has been synchronized.
This way the viewmodel captures all the user needs to know. All the view needs to do is bind to the correct properties for display and editing.
Events occur in our Model and ViewModel that necessitate creating the appropriate View. The question is how to do this and avoid having any View code in the VM or M?
Here's the sequence of events so you can see this dilemma:
The user sets a number fields in a form to start a long running background process and then clicks the "Start" button. If this long running process succeeds then it needs to popup a chart with graphs to show the results. However, if the data fails processing for any reason then it can't popup charts, instead it logs an error message which is show in the a text box on the form.
Right now, that start button calls a method in the ViewModel which actually starts the background thread.
Only the background can determine when or if to create the view.
Currently we have this working by using an interface called ChartInterface. The view implements this interface and then sets a callback delegate all the way down to the backend model. When it decides to create the Chart it invokes the callback and uses the interface to pass the appropriate data and such.
However, this presents a problem because it can potentially produce dozens or hundreds of charts. So we need to have a "Dashboard" with a list of all the charts for the user to select which one to see.
So now the backend needs to decide when or if to create the Dashboard View, then add Chart View to it.
So it's getting messier because there will be increasingly more of these situations as we have lots of Models that need views so creating tons of callback delegates gets ugly fast.
An idea that seems to simplify instead of lots of callbacks will be to only pass an interface to a ViewBinder to the backend. Then each time it creates a model object, it can pass it to the ViewBinder to see if it wants to bind any view object to it.
Our thinking is that most any of the backend objects will be interesting (eventually) to monitor graphically. So if everyone of them after contructing is passed to the ViewBinder interface, then the view can decide if it wants to bind anything to it.
This is sounding better all the time.
The answer became clear while working on the code.
public interface ModelBinderInterface {
void TryBind( object model);
}
instead of one global "server locator" it's more natural for EVERY view object to implement this interface.
Then when it creates any ViewModel objects it assigns itself to the ModelBinder property of the the viewModel object.
Now the ViewModel can pass this same interface to the back end process.
When ever any relevant model gets instantiated, then it calls the ModelBinder with the object.
Then the View object can decide if it can instantiate the object, if not, it can pass the call up to it's parent which also implements ModelBinderInterface.
This way each view can handle instantiating views that it understand whether that be adding a control to a DataGridView or binding the object to a ListView, etc.
Of course, this still allows for a singleton ModelBinder because the lower levels can keep handing the call up to the top level application ModelBinder which there's only one and it can offer singleton instances.
We are working with the MVP pattern, and I was wondering how to deal with GUI actions.
For instance, when the user wants to delete a row from a grid, the user presses the delete button. At this point you can do two things:
1) Call _presenter.DeleteRow() and the presenter then calls _view.SelectedRow. Then the presenter calls view.AskUserForConfirmation(), and when it gets back DialogResult.OK, the presenter actually deletes the underlying object and refreshes the grid.
2) The form asks the user for confirmation and when the DialogResult is OK, then presenter.Delete(myObject) is called OR presenter.Delete() is called and within the Delete method the object is retrieved by calling _view.SelectedRow.
How do you handle these kinds of situations?
The MVP Pattern is supposed to separate your logic, view, and data access. So when trying to decide where something should go, ask yourself if there is actual business logic in what you're trying to do.
Would you want your business layer to have logic about displaying a pop up window? Probably not. It is just a confirmation message. You may want to have a helper class that generates your stylized pop up window, but that is seperate from your Presenter layer.
Option 2. Asking for confirmation is a UI responsibility that the presenter shouldn't need to worry about. I don't involve the presenter until it's time to actually do something to the model, or until some complex business logic needs to be invoked.
This doesn't mean option 1 is invalid. It just creates unnecessary view/presenter chatter, in my opinion.
I am trying to implement the MVP pattern for WINFORMS. Its a simple for with a button and a Grid, on button click, the grid will load, and user can fill in values into the grid.
For my button click event, I have something like this:
_presenter.LoadGrid();
Which is simple and straightforward.
My question is, in regards to grid...
I am planning to have a row click event firing....for enabling/disabling the subsequent input fields for the specific columns/rows of the grid etc.
I understand that the presenter should not contain any GUI elements and the View(form) shouldn't really contain Logic?
So, to have that GridRowClick event firing, I need to manipulate the grid (GUI) based on business rules (Logic). I am lost between letting the presenter handle the logic of that click event or the form?
If the presenter is to handle the click event, wont that include the gui components?
If the view is to handle the click event, the fieldnames etc are all business driven(logic), dynamically binded based on datatable returned from the business layer.
Any advice will be much appreciated.
Cheers
There are (at least) two variants of MVP.
Passive View Pattern
Supervising Controller Pattern
Passive View, as its name suggests, treats the UI as a more or less passive interface between the user and the application. It moves as much testable code to the presenter as possible leaving the view to handle only the most basic UI updates.
Supervising controller gives the view a little more responsibility by letting it handle data synchronization. This is usually done through data binding.
In either case event handling is accomplished by delegating to a presenter method:
EventHandler()
{
presenter.HandleEvent();
}
If handling the event requires making changes to the form, you expose what needs to be updated as a property:
public string PropertyThatNeedsToBeUpdated
{
get
{
return Control.Property;
}
set
{
Control.Property = value;
}
}
For Passive View, grids are a hurdle. Their complexity make it cumbersome to capture all the possible events. With Supervising controller, grids are much easier since you leave data synchronization up to the data bound controls.
You have to make the judgment call as to which is more appropriate for your situation.
The key is getting all that business logic into the presenter where it's testable.
The view should call the presenter to perform the business logic, passing the information needed (e.g. the data associated with the clicked row).
The presenter then performs the business logic and updates the data.
Depending on what type of changes you need to make, that might be all you need to do, since the existing data binding might be sufficient to update the view automatically. If it isn't sufficient, the presenter can make one or more calls to the view (via its interface of course) in order to make the required changes.
As you say, you should aim to minimize the amount of non-trivial code in your view, and in particular, the view shouldn't have any business logic in it.
EDIT:
Some good general information on MVP and other presentation patterns here: http://martinfowler.com/eaaDev/uiArchs.html
You might want to check out Part 4 of the video series from Polymorphic Podcast. He uses the supervising controller pattern and shows a technique for handling data grids. The whole series was actually a good introduction for me.
http://polymorphicpodcast.com/shows/mv-patterns/
What is the best breakdown of responsibility when using a virtual grid and the MVP pattern in a winforms application.
including:
Getting callbacks from the grid on user changed cell updates
Callback from the grid to set the style and value of a cell given a row and column
The exact responsibilities in the many patterns that are referred to as Model-View-Presenter vary. Mainly they vary about how much control is exerted over the view by the presenter. Martin Fowler has an in depth discussion of a number of different variants in his chapter on GUI Architectures, it's well worth a read.
Have a look at Presenter First as it deals with adapters and the responsibilities in some depth.
Both Passive View and Supervising Controller are worth looking at.
model (or domain model) == logical representation of the entities involved in the system including their state and behaviour
presenter == listen for events from view (and maybe model) and service those requests, convert model types into view types (passive view), this is really plumbing to hide the view and the model from each other. Reacts to stimulus from the user.
view == presentation: the visual representation of the model that the user can interact with, collecting user input
Your specific questions around the callbacks and getting the grid cell style are both going to involve the view handling events from grid and raising events back to the presenter to request actions or retrieve data from the model. This is perfect for the callback when the cell content is updated (this needs to be published to the presenter so that the presenter can validate the change in the model and make the change in the model).
For the grid cell style I am thinking that some sort of adapter in the view may need to translate the state from the model (retrieved via an event from the view to the presenter) into the grid cell style information. This could happen in the presenter but I would personally prefer the presenter not to have knowledge of the widget in the view.
If I understand you correctly, the grid is part of the view implementation and is not visible to the presenter. In that case, the presenter should not need to know how the data is displayed, only how to provide them.
I would probably create a helper class, an adapter of some sort, which the grid communicates with. The grid sees nothing but this helper, ditto for the view.
The collaboration would be something like:
grid <-- helper <-- view <--> presenter