In the last post I looked at what, exactly, MVC really is. Now I want to look at how it applies to Windows applications.
Windows Forms with data binding is basically Active MVC! The data binding keeps the view and the model up to date automatically. When the user performs an action (like clicking a button) an event is fired. Some code executes in response to the event, updating the model and causing the view to be updated. Just like in Active MVC. The only difference is we did it all in two classes, the form class (view & controller here) and the data class. We could separate the controller into its own class if we wanted to, and then we'd have the M, the V, and the C.
Are we comfortable with this? The only problem is that in Active MVC the Model takes on more responsibility because its responsible for keeping the view up to date. But if we're data binding to the model, it has to be 1-1 with the controls we're displaying. There is some potential for this to get complicated if we need our Model to do more advantaged state management. This could cut two ways and could be a great thing, or could become really hairy very quickly.
We could convert this to look more similar to Passive MVC by creating two models. One model will be independent of the view and managed completely by the controller. The other model will be the class we use to data bind into the View. This second model will be updated by the controller to cause values of the view to change and be read/monitored by the controller to respond to user events. With this setup we've moved more of the responsibility to the controller but we've also increased the amount of data passing that has to go on.
And there in lies the rub. On the web, the data passing is required, there is no way around it. But in a windows application, we don't have to pass data around like this. We can write code that gets the data directly from the controls and writes them to the database if we want to. There is no need to have a model class for housing data.
So what are we gaining by using MVC in a Windows Application? We've separated the data from the GUI and we've also separated the "controller" logic from the GUI. This will be nice if we ever want to make changes to the GUI like swapping one control for another. Its also nice because we can now write unit tests for the controller and mock out the GUI (and the model if needed).
So the big question is, are the benefits of an MVC design worth the overhead that comes with an MVC design?
To start with, its certainly not good to have a single form class that contains EVERYTHING. In Windows Forms this is how nearly everyone writes, at least when they're starting out. It seems like the simplest option: 1 form, 1 file, 1 class. Everything is in one place!
But as the form gets bigger (more controls, more rules, more behavior) the number of event methods just keeps rising and before too long you're looking at a 2,000 line class (not including designer code...). You can't remember where anything is and you can't find anything either. It feels like being lost in a jungle.
So we need to come up with a way of breaking this into pieces, no question. We just have to decide what pieces we want. MVC provides us with three pieces. They are nice logical pieces in theory. In practice, you really have to commit to "shoveling data around."
If you were hoping I'd end this by telling you what the best practice is, I'm sorry to disappoint, because I don't know. I'm still experimenting and researching. I'd love to hear your take, or your best practice, or even approaches you've tried and despised.
Update 1/25/08: Added chicken scratch images
Update 9/22/08: Follow up post about MVP and MVC which may be more applicable to Windows Applications and talks about View State.
One way ive seen this implemented is making each action/ event execute a command. Your set of commands acts as your "controller" and they act upon a data model.
ReplyDeleteThis keeps your form class clean (one line methods basically) and segments the different actions into their own classes. Also pretty easy to unit test the commands
How does the view get updated in that arrangement? Does each action class have a handle to the view so they can tell it what to do? Or does the view monitor the data class for updates?
ReplyDeleteI totally agree that the traditional WinForms practice just feels "yucky." I've been trying to remove my logic from the form class and into a controller class for a few weeks now, but somehow Rails just makes it so much easier. I can't seem to figure it out in C#.
ReplyDeleteI just noticed you replied to this comment.
ReplyDeleteBasically yes. The commands tell the view what to do. If the action the view takes is complicated (say binding a dataset to a grid) the view might have a method exposed through an interface called BindMyDataGrid(Dataset data) and your controller calls View.BindMyDataGrid();
For testing the controller mocks out the view.
I like that. Rather than having one big controller class with many methods for each action, you have many "action" classes each performing one job.
ReplyDeleteYou could mix and match between 1 controller and many controllers (actions) depending on the complexity of the View.
Quite nice!
i think i actually like the word action for it too. I might switch to that. We do a model similar to what im describing at work and I'm trying to find a way to translate it to the PHP stuff i do at home. So now on all my forms ive added a hidden field called postback. If a form submits to itself postback will be set. If set it executes a Save or Process Action.
ReplyDelete