Model / View / Presenter
Over the weekend I did a lot of reading about the Model/View/Presenter development paradigm, and tried my hand at a few coding examples.
The idea behind MVP is that you take all the logic that would normally tie your user interface (the View) to your data (things like populating TextBox controls, or validating user input) and move it back into a class of its own (the Presenter). This means that your UI (Forms, UserControls etc) becomes very "thin", and can easily be swapped out for some other design.
Since the logic of the program isn't tied up in the UI, MVP also makes it easy to design a test framework to make sure your business logic is sound.
In a way, it's almost like MVP is a replacement for data binding. It's a little more code, but could be worth the effort in the long run.
The example I was playing with at home was a way to view a "folder" in Comicster. A folder only has two properties - an ID (a Guid) and a Name (a string), so it's a pretty simple thing to view on the screen. I started by creating a simple class to represent the folder:
public class Folder { public Folder() : this(Guid.NewGuid()) { } public Folder(Guid id) { _id = id _name = "New Folder"; } private Guid _id; private string _name; public Guid ID { get { return _id; } set { _id = value; } } public string Name { get { return _name; } set { _name = value; } } }
So now I had a "model" to work with. In reality this would probably be a FoldersDataRow - a row from the Folders table in my typed DataSet.
Next I had to create the interface that my "view" would implement. Again, the idea of MVP is that the view is pretty dumb and easily replaceable, so it shouldn't need to know too much about the implementation of other parts of the program. The view interface, then, just needs to look like this:
public interface IFolderView { Guid ID { get; set; } string Name { get; set; } event EventHandler Update; }
I've included an "Update" event in that interface so that the UI has some way of notifying the presenter that the user wants to update the folder. For example, the user has changed the folder name TextBox and clicked the OK button.
Next I need to create a form that implements this interface, so that the presenter layer has something to talk to. I just whacked a TextBox and a Button on there and ended up with something like this:
public partial class FolderForm : Form, IFolderView { /* ... */ private void button1_Click(object sender, EventArgs e) { if (Update != null) { Update(this, e); DialogResult = DialogResult.OK; } } private Guid _id; public Guid ID { get { return _id; } set { _id = value; } } public string IFolder.Name { get { return textBox1.Text; } set { textBox1.Text = value; } } public event EventHandler Update; }
This form, then, is just a dumb way of displaying the individual parts of a folder. It doesn't know anything about the "Folder" class (or FoldersDataRow, or whatever).
The last piece of the puzzle is the presenter - the class that takes a folder and tells the UI about it:
public class FolderPresenter { public FolderPresenter(Folder folder, IFolderView view) { _folder = folder; _view = view; _view.Update += UpdateFolder; } private Folder _folder; private IFolderView _view; public void Initialize() { _view.ID = _folder.ID; _view.Name = _folder.Name; } public void UpdateFolder(object sender, EventArgs e) { _folder.ID = _view.ID; _folder.Name = _view.Name; } }
So this "FolderPresenter" class is constructed with an instance of a folder, and a way to view that folder. It can then populate the view with the details of the folder. The view doesn't have to know that the folder is represented in the model as a Folder class - it just has to know that the folder has an ID and a Name.
In our main form, then, where we have a folder and want to show the "edit folder" dialog, we do something along these lines:
private void ShowFolder(Folder folder) { FolderForm f = new FolderForm(); FolderPresenter p = new FolderPresenter(folder, f); p.Initialize(); f.ShowDialog(); }
And we're done!
Now, I still have some questions about this methodology. Like, what's the best way to present the user (the view) with a list of objects (a grid, for example)? And how much logic can I pull out of the view? For example, if I can edit or delete a folder, should I have a presenter that handles that, too? Maybe a "ViewFolderPresenter" which knows how to edit and delete a folder, and if you want to edit it it does the work of creating an "EditFolderPresenter" etc.
I will definitely kick on with the idea and see where it leads. It seems like a great way to build a UI using current technologies (Windows Forms or ASP.NET) and be able to swap in something more advanced (WPF or WPF/E) later on.
I recommend checking out Jean Paul Boodhoo's DNRTV episode on MVP, too. It was the first time I'd seen anything about the pattern.
Comments
# Rob Farley
28/08/2006 9:56 AM
If you do a lot with this stuff, could you become an MVP-MVP ??
Rob
# mabster
28/08/2006 10:04 AM
ROFL! Yeah, that'd be the way to go!
Do you use this methodology yourself, Rob?
# bob
26/05/2007 3:18 AM
What if the Update event fails and you don't want to close the form, but want to present an error message?
# mabster
26/05/2007 8:42 AM
Good question, bob.
I think perhaps you could add an "Updating" event which was of type CancelEventHandler. That would let the view cancel the update if there was a problem.
Or throw an exception from the view and make sure your UI can handle it.
# David Walden
4/12/2007 11:14 AM
Mabster,
How would you handle a folder browser dialog on your winforms using MVP? How does the presenter deal without a concrete ref to system.windows.forms?
Cheers,
David
# mabster
4/12/2007 12:59 PM
Beats me! I never actually did any of this stuff! This post was more about me trying to rationalize what I'd learned about MVC from reading other blogs etc.
Presumably the "model" is the file structure, the "view" is a form with a TreeView and a few buttons on it, and the "Controller" ("Presenter") is a class that populates the form's TreeView with folders.
Then you'd have a FolderSelecting and FolderSelected event on the view to let the controller determine whether the folder is allowed to be selected.
Something like that! It's an example that seems to be just made for the MVC concept.
# purple
18/12/2007 6:20 PM
Hi Mabster, I am new to MVP. Can provide the source code to download? I think through this way, it can help me to get the better understanding. Thank
# mabster
18/12/2007 6:31 PM
There IS NO source code, purple. You're looking at it in this post. Writing this post was just my way of thinking out loud about MVP.
# Jerry
12/04/2008 8:48 AM
Thanks for the example. Needed one to make sure I was getting the implementation through my thick skull, and this has helped to cement the idea in. Really appreciate it.
# Ankit
2/10/2008 8:47 PM
This structure is very good. For Big application this structure is very important.
Regards,
ANKIT CHAMPANERIYA
(Software developer,MCP,MCTS)
# mvp boy
30/10/2008 4:18 AM
"How would you handle a folder browser dialog on your winforms using MVP? How does the presenter deal without a concrete ref to system.windows.forms?"
the answer is, the presenter should have no concept of windows, only workflow. When launching a new screen, dialog, messagebox, a workflow system should be doing the heavy lifting here. It should never be the job of a form to launch another form. It should be the job of a form to notify the workflow subsystem that it needs a new screen to be launched.