Winforms MVP Grid Events Problem - c#

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/

Related

How to catch PropertyChanged events in multiple Views?

I recently started learning about WPF, which led me to learn about MVVM and eventually MVVM Light, so still a starter in these three. I am building an application with a layout similar to the picture in the link -> Application layout
In order to maintain good code separation and avoid huge files i decided the best approach would be to create a main View, and in that create several smaller Views per "zone" of the UI. From what i read in several tutorials, it is advised to maintain 1 ViewModel per View. Therefore i have a Master View / ViewModel, and several View / ViewModels running simultaneously.
Finally i have a single Model that keeps track of the information I plan to display in the UI. The Model interacts with an external API that can modify the data in it. So besides data being modified by user request (ex: pressing buttons or timers), the data will also change with asynchronous events from the API. Which means I need two way communication between the Model and the ViewModels / Views.
The questions:
1. Do you agree with the "1 view per zone of the UI"? And the 1 ViewModel per View?
2. In the Main View-Code-Behind I instantiate all the ViewModels, and in each View I bind them like in the MVVM Light examples i saw:
<UserControl ... DataContext="{Binding Main, Source={StaticResource Locator}}">
<UserControl ... DataContext="{Binding SideBar, Source={StaticResource Locator}}">
<UserControl ... DataContext="{Binding TopBar, Source={StaticResource Locator}}">
Is this the correct way to instantiate and bind several ViewModels to the respective Views?
3. Each ViewModel is passed a reference to the Main ViewModel (except the Main itself) in its constructor, which is the only one with a reference to the Model. This is how i connect the several ViewModels to the Model. Is this conceptually correct?
4. Initially i was trying to avoid using MVVM Light or other frameworks if i could do all i wanted with the RaisePropertyChanged method. I might be doing something wrong, but for example, when the Model calls RaisePropertyChanged, i can catch that event in the Main ViewModel, however it doesn't propagate to the rest of the ViewModels, so i had to do it myself by calling RaisePropertyChanged a second time:
public MountainTopViewModel()
{
_model = new MachineStatusModel();
_model.PropertyChanged += ModelPropertyChanged;
}
void ModelPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "TestVarModel")
{
// do something else if needed
RaisePropertyChanged("TestVar");
}
}
I'm guessing this is either not the correct way to do it, or there is a better one. So how can I inform all the Views and ViewModels when a property changes in the Model, without having to re-call the method in different places?
Sorry for the long story, i would appreciate some help.
This seems unwise to me:
The Model interacts with an external API that can modify the data in it. So besides data being modified by user request (ex: pressing buttons or timers), the data will also change with asynchronous events from the API. Which means I need two way communication between the Model and the ViewModels / Views.
I would have the async API events driving changes in the viewmodel, not the model. Then, in response to changes from the async API or from the View, the viewmodel does its usual thing: Updates the model and raises events which the view responds to. The viewmodel already plays that role, so use what you've got. Your scheme adds complexity that you don't need, and it's more complexity than you may realize. Item # 4 in your question is just the tip of the iceberg of that added complexity; believe me, it'll only get uglier from there. Don't do that to yourself. You're young. You've got everything to live for.
It's not unusual for a viewmodel to handle the PropertyChanged event of another viewmodel, or for a viewmodel to expose specific custom events which fire when specific properties change value. It might have a NameChanged event or whatever. But I don't see any particular need for that in your question, as I understand it.
1. Yes.
2. If MVVMLight does things the way you've got it there, do that. Plunkett's Razor: Whenever possible, conform to the practices of the framework you're using. Consistency is golden in programming for many reasons, and if you follow the "rules", you'll usually find the framework will be there waiting to help you instead of fighting you every step of the way. This isn't a law of nature, but it's an amazingly reliable rule of thumb.
3. That's conceptually a little shaky. Ideally, we try to write viewmodels that aren't dependent on "parent" viewmodels. Your Library viewmodel has to know what a Book viewmodel is because it contains a collection of them, but a Book viewmodel can often be more useful if it doesn't depend on a Library. Imagine writing a Wheel that's got all kinds of dependencies on Car, and then having to implement Bicycle. Do you give Bicycle an Alternator, or do you create a dummy Car? Times like that you start to daydream about moving to a commune in Vermont and making useful objects out of wood.
I would probably have a model type for each viewmodel, and give all the viewmodels a reference to their own model in their constructors. The models would probably have the same parent-child relationship as the viewmodels. If your model is Entity Framework or something instead of "POCO" classes, then yeah, one model for everybody or whatever. But still, just hand it to them directly.

What is the correct way to pass controls around?

I am creating a new winforms application that will have datagridviews which will load matrix data, and I want the user to be able to do a bunch of operations on the data, like showing/hiding columns, editing cell values, and filtering too.
I thought of using the MVP pattern (Model, View, Presenter).
I wanted to create a presenter class, which would handle all the logic (meaning any events that the user triggers), eventually end up in the presenter which will work on the raw data (the matrices). This seems logical up to now but my question is what do I do if I want to pass the controls themselves (like the datagridviews)? Should these controls be sent the presenter class or is that bad design?
Perhaps it's better to find ways to only modify the raw data and then update my datagridviews?
It is not a good idea to pass around controls. If you're going to use a pattern such as "MVP", then you should have the "model" contain the representation of the "view". In this case if there are various details pertaining to a set of data it belongs in the model. Then you pass the model around.
Perhaps it's better to find ways to only modify the raw data and then update my datagridviews?
So, to answer this question, "yes". Use the model to wrap the data and pass it around.
Update
Specifically, with WinForms controls belong to containers, being that they are reference types and have lots of exposed events you run a HUGE risk of passing a reference from one Form to another Form. Now, imagine that the first Form is done being used and closes and disposes, it kills the reference to the control and attempts to unwire events. Do you see where I'm going with this? It quickly becomes a nightmare trying to correctly cleanup references, and un wire event handler and since controls belong to one container by design it breaks that paradigm.
It's better to have a separation of concerns. If you need a view to have certain data, it's always best to pass around the data itself...

Design pattern for ListView control having 2 states?

I have ListView control in windows forms that is due to display list of items in either icons view or in details view. I'd like to separate the ListView state logic and created 2 states classes IconsState and DetailsState inhereting them from IState having all the methods to be called from UI window.
In details view there is RetrieveVirtualItem event and in icons view there is DrawItem event. In order to call them from IState variable present in UI both States descendant classes have to implement them. Having DrawItem in DetailsState does nothing but return. The same for RetrieveVirtualItem in IconsState.
Is there another design approach to avoid implementation of empty methods in states?
Yes, there are better approaches. It's a design smell to force a class to have a member that is not supposed to be in there, ie in your words "Having DrawItem in DetailsState does nothing but return".
Alternatively, you can use an MVP pattern, which will allow you much greater testability. In a passive view variation of MVP you will have one model, two dumb views and a presenter that decides which view to render depending on the user choice.
Additional resources on MVP:
SO tag for MVP
Passive view sample
MVP examples for Windows Forms

Does the Presenter Perform GUI Logic in the MVP Pattern?

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.

Model - View - Presenter with Virtual Grid

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

Categories

Resources