Model view presenter - setting object collections

D

Doug

Hi,

I learned a little about the model view presenter pattern at a
conference this last week and am experimenting with it. It's working
pretty well but I have a question.

I am trying to use it to reset info in a combo box. Below is some
sample code for my view interface and the presenter:

public interface IDevToolView
{
string[] Tables
{ set; }
}

public class DevToolPresenter
{
private IDevToolView _view = null;

public DevToolPresenter()
{}

public DevToolPresenter(IDevToolView view)
{
_view = view;
}

public void GetTablesForNewDatabase()
{
string [] tables = //Some code to get the string array of tables

if (tables.Length != 0)
{
_view.Tables = tables;
}
}
}

and here's what my view looks like (just the sample for what I need for
this question:


public class frmMain : Form, IDevToolView
{
public string[] Tables
{
set
{
cboTable.Items.Clear;
cboTable.Items.AddRange(value);
}
}
}

My question is around the call to Items.Clear in the Tables property.
This seems to me to violate the pattern, I should really be doing that
within the presenter if I understand the pattern correctly. However,
short of passing in the combo box itself into the presenter, I can't
seem to get around it, because I don't have any way to access
cboTable.Items directly.

Am I misunderstanding this? Is there a way around my problem?
 
D

Dave Sexton

Hi Doug,

I think your code is fine as is.

For one thing, clearing the items is not exactly business logic - it's view
logic. In other words, you might want to create a different view in the
future that doesn't clear the display before it's updated with different
tables. Think painting program, for instance, just to visualize why clearing
the display should really be up to the view itself. After one stroke, the
controller might send another, and you may just want to keep the previous.

And the reason you stated already is a good one, "I don't have any way to
access cboTable.Items directly". That's right, you don't! And if you did
you'd be tasking view-logic to the controller.
 
D

Doug

Hi Dave,

The class I have for resetting that data in the combo box isn't really
a controller so much as it is a presenter class. I'm relatively new to
the presenter pattern, but from what I understand, the presenter
actually does the work of filling/reseting the view? In that case,
wouldn't I want the combo box reset in the presenter class somehow?

I've gotten the impression that the presenter class is very similiar to
a controller class but that its really just another layer of
abstraction that allows for better testing of your code and a more
lightweight view overall.
 
D

Dave Sexton

Hi Doug,

"The Model View Presenter design pattern is really just a fresh take on the
Model View Controller pattern that many developers are already familiar with;
the key distinction is that MVP truly separates the UI from the domain/service
layer of the application"
[Model View Presenter Pattern on MSDN:
http://msdn.microsoft.com/msdnmag/issues/06/08/DesignPatterns/]

It appears the you are correct - MVP is not exactly MVC, however this small
snippet states that MVP is meant to "truly" separate the UI from the
domain/service layer. To be perfectly honest I don't know what "truly" means
here, but then again I haven't read the article yet myself.

Just an initial guess, but I take it that MVP actually differs from one aspect
of MVC - The controller is independent of the view and model, however I
suspect that for each view you code in the MVP design, you'll have to code a
corresponding presenter as well. Seems like more work to me - I could be
wrong though :)

But I'm going to recommend that you take my original advice anyway. Try not
to tailor your program to fit a design pattern unless it's absolutely
required. If you like what you have already and it's just this last concept
that's bugging you, my solution was quite easy - leave it alone!

If you aren't going to be writing any more views then both MVP and MVC really
won't be that useful at all. In WinForms, the view and controller are usually
the same thing and the model is a business object or a DataSet. This simple
paradigm usually works quite well for general application development. If you
properly encapsulate the business logic outside of each Form and into its own
object model, then you can really reduce the amount of code in the Forms,
normally letting the Form present itself.
 
J

Joanna Carter [TeamB]

"Dave Sexton" <dave@jwa[remove.this]online.com> a écrit dans le message de
[email protected]...

| Just an initial guess, but I take it that MVP actually differs from one
aspect
| of MVC - The controller is independent of the view and model, however I
| suspect that for each view you code in the MVP design, you'll have to code
a
| corresponding presenter as well. Seems like more work to me - I could be
| wrong though :)

I have been in the business of designing an MVP framework, based on the
Taligent papers, first for Delphi and now for C# and WinForms, for some
years now. A true MVP implementation is not "just another MVC", it is more
sophisticated than that, having extra classes that help separate the View
(UI) from the Model and Presenter.

MVP should consist of: Model View and Presenter, but there are other classes
attached to both the Model and the Presenter.

The Model should also contain the Value, a Selection and a Command Set (a
list of Command objects).

The Presenter should also contain one or more Interactors.

Selection in the View should be purely a reflection of the Selection in the
Model; in the case of the Value being a single object, the Selection is
always the whole (object) Value, but in the case of a collection, the
Selection will contain a list of items from the (list) Value.

The Command Set should be an Observer of the Selection and should change
which Commands are available relative to the context of the current
Selection. e.g. in the case of a List Model, you will have Commands like
Add, Remove and Insert; if the Selection is empty, then the only Commands
available should be Add, as Insert and Remove both require a target on which
to act. As Soon as one item is added to the Selection, the Insert and Remove
Commands are made available, but when the Selection contains more than one
item, Insert becomes disabled as you cannot insert an item on a multi-item
target.

The job of the Interactor(s) in the Presenter is to catch events from the UI
element and translate them into calls to the Commands on the Model. this
way, you don't need to write event handler code in either the View or the
Presenter, allowing you to swap UI elements without changing the code in the
Presenter.

It is usual, however, to have to write a hierarchy of Interactors for any
particular hierarchy of UI controls, but the only public interface to
interactors is so simple that this does not affect the code in the
Presenters.

MVP is not intended to work only on a single form per object basis, but is
intended to be nested so that controls that reflect properties of objects
should have their own MVP "components" to link the control to the property
of the object.

Forms for whole objects should be linked to those objects by means of an MVP
"component" that contains one nested MVP "component" for each property of
that object.

Complex object scenarios use appropriately more complex MVP components that
may be nested to several layers, one for each "layer" in the complex Model.

In this manner, replacing the Interactor for a complex object for one UI
library would also cause the nested Interactors to be replaced because they
are created inside the complex Interactor.

Does that help clarify anything ?

Joanna
 
D

Doug

Does that help clarify anything ?

Hi Joanna,

Yesterday, I had actually read through some stuff on this pattern that
you have put together so I'm not surprised you responded...:)

If I understand you correctly, I did know that you could build
"Adapter" classes that wrap control functionality (i.e. A combo box
adapter that would let me clear out the values as I described in my
intial question). This way I could do a "Windows combo box adapter"
and a "Web combo box adapter" if desired. I'm not real sure I want
that level of abstraction though at this point for the app I'm
designing. It would definetely be worthwhile to consider if/when using
this pattern overall.
 
D

Dave Sexton

Hi Joanna,
Does that help clarify anything ?

Lol - Yes, it does :)

It seems to me now that MVP is meant to abstract behavior from the UI in a way
that the MVC architecture does not. (But that comes with a price: complexity)

Model
--
Value - encapsulates all state (e.g., list of people)
Selection - represents the current, logical state (e.g., Fred)
Commands - actions that may be performed on the state (e.g., "Add", "Remove")

Presenter
--
Interactors - half/full duplex adaptation of UI behavior into Commands

View
--
UI components


MVP uses components (Interactors) that can adapt user events into commands
that the model understands, for each UI component and relationship between two
or more UI components. The reverse must be handled as well so that commands
can be translated into instructions that the UI components can process. MVP
uses the Observer pattern (managed event pattern now, I assume) to listen for
changes in the model's state, then constructing the appropriate set of Command
to encapsulate the actions that can be performed on the model.

Please allow me to take on the role of devil's advocate, for the moment :)

A common implementation of the MVC architecture is to use inheritance and
business objects. i.e., WinForms provides the View logic, and we simply
derive from Form or Control to add all of the controller logic. We use
business objects as the models and can bind directly to the View components in
many cases when abstraction isn't required.

I'm not so sure still that the MVP architecture's value outweighs it's
complexity.

MVC is quite simple, common, doesn't require the tangible representation of
behavior through commands, and therefore doesn't require adapting user input
into an object model, and provides a usually acceptable level of abstraction
when business objects (models) are used judiciously.

Any extra plumbing in a design pattern is just asking for more bugs.

That stuff said, I do like the pattern. As a matter of fact, I can see the
benefit of abstracting the behavior out of Form and Control subclassing and
into dedicated components. But I'd be wary of its inherent complexity and
whether it would actually be worth implementing when choosing a suitable
architecture for a solution.

Do you know of any in-depth articles that detail the complexities of the
pattern even further?

--
Dave Sexton

Joanna Carter said:
"Dave Sexton" <dave@jwa[remove.this]online.com> a écrit dans le message de
[email protected]...

| Just an initial guess, but I take it that MVP actually differs from one
aspect
| of MVC - The controller is independent of the view and model, however I
| suspect that for each view you code in the MVP design, you'll have to code
a
| corresponding presenter as well. Seems like more work to me - I could be
| wrong though :)

I have been in the business of designing an MVP framework, based on the
Taligent papers, first for Delphi and now for C# and WinForms, for some
years now. A true MVP implementation is not "just another MVC", it is more
sophisticated than that, having extra classes that help separate the View
(UI) from the Model and Presenter.

MVP should consist of: Model View and Presenter, but there are other classes
attached to both the Model and the Presenter.

The Model should also contain the Value, a Selection and a Command Set (a
list of Command objects).

The Presenter should also contain one or more Interactors.

Selection in the View should be purely a reflection of the Selection in the
Model; in the case of the Value being a single object, the Selection is
always the whole (object) Value, but in the case of a collection, the
Selection will contain a list of items from the (list) Value.

The Command Set should be an Observer of the Selection and should change
which Commands are available relative to the context of the current
Selection. e.g. in the case of a List Model, you will have Commands like
Add, Remove and Insert; if the Selection is empty, then the only Commands
available should be Add, as Insert and Remove both require a target on which
to act. As Soon as one item is added to the Selection, the Insert and Remove
Commands are made available, but when the Selection contains more than one
item, Insert becomes disabled as you cannot insert an item on a multi-item
target.

The job of the Interactor(s) in the Presenter is to catch events from the UI
element and translate them into calls to the Commands on the Model. this
way, you don't need to write event handler code in either the View or the
Presenter, allowing you to swap UI elements without changing the code in the
Presenter.

It is usual, however, to have to write a hierarchy of Interactors for any
particular hierarchy of UI controls, but the only public interface to
interactors is so simple that this does not affect the code in the
Presenters.

MVP is not intended to work only on a single form per object basis, but is
intended to be nested so that controls that reflect properties of objects
should have their own MVP "components" to link the control to the property
of the object.

Forms for whole objects should be linked to those objects by means of an MVP
"component" that contains one nested MVP "component" for each property of
that object.

Complex object scenarios use appropriately more complex MVP components that
may be nested to several layers, one for each "layer" in the complex Model.

In this manner, replacing the Interactor for a complex object for one UI
library would also cause the nested Interactors to be replaced because they
are created inside the complex Interactor.

Does that help clarify anything ?

Joanna
 
J

Jeff Louie

Hi Dave... Well this discussion got me thinking (could be dangerous). So
here is what I have come up with. IMHO, WinForms is used traditionally
as a Model- View/Controller. Cocoa (MACOSX) can be done as m-C-v where
the Controller owns the Model and the View and all interaction between
the Model and View goes through the controller. Very simple to
understand. I have tried to graft this simple m-C-v pattern onto Windows
Form, sort of. So it goes something like this. The application logic
goes into a Model class. So for a mortgage calculator

Model : Mortgage.ICalculate implements

public interface ICalculate
{
Mortgage.Calculation Calculate(Mortgage.Parameters mp);
}

where Calculation and Paramaters are immutable thread safe structures.

The Controller is a very small class that adds a level of indirection
between the Form (View) and the Model. The Controller implements IUpdate
and any object can call Update to request a change in the Model.

public class Controller : Mortgage.IUpdate
{
// Controller owns the Model
Model model = new Model();

public delegate void NotifyHandler(object source,
MortgageEventArgs args);

public event NotifyHandler NotifyDispatcher;

public bool Update(Mortgage.Parameters mp)
{
Mortgage.Calculation mc = model.Calculate(mp);
if (mc.IsValid())
{
// fire event to all registered listeners of change in
model state
NotifyDispatcher(this, new MortgageEventArgs(mc));
return true;
}
else return false; // do nothing if input data is invalid
}
}

public class MortgageEventArgs : EventArgs
{
public readonly Mortgage.Calculation calculation;
public MortgageEventArgs(Mortgage.Calculation calculation)
{
this.calculation = calculation;
}
}

Any View(Form) registers an interest in NotifyHandler events as in:

public Form1()
{
InitializeComponent();
controller.NotifyDispatcher += new
Controller.NotifyHandler(Form1_OnINotifyEvent);
}

The Form can request a change in Model state as in:

controller.Update(new Mortgage.Parameters(principal,
interest, months, payment, target));

So the Model and View have no implemtation knowledge of each other.
Multiple View components can register an interest in Model State changes
via Controller events. Any object can request a change in Model state
via the Controller.

Comments welcome.

Regards,
Jeff
 
D

Dave Sexton

Hi Jeff,
Hi Dave... Well this discussion got me thinking (could be dangerous). So
here is what I have come up with. IMHO, WinForms is used traditionally
as a Model- View/Controller.

Yes, I believe so.
Cocoa (MACOSX) can be done as m-C-v where
the Controller owns the Model and the View and all interaction between
the Model and View goes through the controller

Through binding, WinForms does allow the View to directly access the Model,
but whenever binding isn't used WinForms applications are the same; view is
updated by the controller, which also owns the Model.

In a WinForms application it's common to derive from the Form class, for
example, which provides the view logic that interacts with Windows for
presentation. A partial (C# 2.0) class commonly contains all of the
controller logic.

It's common to create business objects or use strong-typed DataSets as the
Models. When binding isn't used, the code in the partial class is actually
controlling the state of the UI based on changes to the data, provided by the
Models, user input and other state-changing events. The controller is
implemented using inheritance and partial classes to remove the need for
redundant event declarations and other unnecessary code bloat that commonly
doesn't add any real value. The code in the partial class is not part of the
Models, nor is it part of the View implementation from which its class
derives, and it does control both the View and the Model. Therefore, it can
be thought of as the controller.

There is usually no need to extract this logic into another component since
that adds a lot of complexity without any real value, in many cases. If you
will need to use multiple views on top of the controller then inheritance
actually becomes more restrictive and encapsulating the controller logic into
another component becomes a reasonable option.

Once you encapsulate the controller logic in a separate component and start
materializing behavior into Command objects you are then using the MVP
pattern, if I've understood it correctly.
Very simple to
understand. I have tried to graft this simple m-C-v pattern onto Windows
Form, sort of. So it goes something like this. The application logic
goes into a Model class. So for a mortgage calculator

<snip code>

This is still the MVC architecture, mind you. The MVC pattern doesn't require
that the View access the Model directly, but it is allowed. In WinForms this
means that you can still consider your application MVC when a Form uses
partial binding and partial controller logic.

Model View Controller:
http://en.wikipedia.org/wiki/Model_view_controller
So the Model and View have no implemtation knowledge of each other.

Again, the same goes for general WinForms applications that don't use binding.
Multiple View components can register an interest in Model State changes
via Controller events. Any object can request a change in Model state
via the Controller.

I agree that if you're planning on reusing that controller logic, as is, by
another UI such as web forms, mobile device forms or in a composite
application screen, then encapsulating the controller logic will probably be a
good idea. Otherwise, I think it's an unnecessary burden.
 
J

Jeff Louie

Hi Dave... Thanks for the feedback. In a sense I guess that I am just
rolling my own connection between the Model and Views using events. For
instance, if I add a MortgageTotalTextBox Component, I can just register
an interest with the Controller and the component is then "data bound"
to the Model via the Controller. The class based demonstration code
looks like this:

// inner class
public class MortgageTotal
{
TextBox tb;

public MortgageTotal(TextBox tb)
{
this.tb = tb;
}

public Mortgage.NotifyHandler GetNotifyHandler()
{
return new
Mortgage.NotifyHandler(MortgageTotal_OnNotifyEvent);
}

public void MortgageTotal_OnNotifyEvent(object source,
MortgageEventArgs arg)
{
Mortgage.Calculation c = arg.calculation;
if ((tb != null) && c.IsValid())
{
// some complex logic/graphics goes here :)
double total = c.Payment * c.Months;
tb.Text = String.Format("${0:N}",total);
}
}
}

In the Form1 class I can do this:

public Form1()
{
InitializeComponent();
MortgageTotal total = new MortgageTotal(textBoxTotal);
controller.NotifyDispatcher += new
Mortgage.NotifyHandler(Form1_OnINotifyEvent);
controller.NotifyDispatcher += total.GetNotifyHandler();
}

Regards,
Jeff
 
D

Dave Sexton

Hi Jeff,
Hi Dave... Thanks for the feedback. In a sense I guess that I am just
rolling my own connection between the Model and Views using events.

I agree.
For instance, if I add a MortgageTotalTextBox Component, I can just register
an interest with the Controller and the component is then "data bound"
to the Model via the Controller.

Well, not exactly. Data-binding in WinForms goes much deeper than simple
event registration. True data-binding would be automated. It wouldn't
require you to write custom events each time you needed to "listen" for
particular changes in state.

<snip code>

Do you agree that there is no apparent value in this design if you are using
(and will always be using) only one View?

One view per controller is the common scenario in WinForms applications, so I
prefer the classic WinForms MVC architecture over any others I've seen thus
far for its simplicity, intuitive nature and flexibility when real
data-binding can be utilized.
 
J

Jeff Louie

Hi Dave.. Well I am having some trouble with my browser. I agree that
the
approach I posted adds unneeded complexity to most programs, but I am
having fun flexing my brain cells and moving outside of my comfort zone.
The
code I posted seems to present a fairly simple way to drag and drop
multiple
custom GUI components and "bind" them to a particular _state_ of the
Model
using events. It is possible to have multiple sets of View components
"bound" to
different Model states. It is hand coding, but it is hand coding that I
can
understand.

http://www.geocities.com/jeff_louie/OOP/oop3.htm
http://www.geocities.com/jeff_louie/oop31.htm

Regards,
Jeff
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top