But now I fear that I've created an endless loop! For example, if I press
the 'Yes' radio button then this in turn calls the internal handler, which
then sets the property value in the Model to "true". But then the code in
the Model, seeing the property being changed in turn calls the event handler
back on the form.
As Jeff has indicated, this kind of relationship cannot be resolved when you
only have a Model and a View.
This is why someone came up with the concept of MVC (Model View Controller)
and later with MVP (Model View Presenter), a more sophisticated and flexible
version of MVC
In MVC, the Controller acts as a Mediator between the Model and the View and
can ensure that, if a message comes from the View, that the resultant action
invoked on the Model does not cause infinite recursion.
MVP takes things further by splitting out the responsibilities for handling
changes even better.
I have had extensive practice in implementing an MVP framework using Delphi
which adds a couple more ideas to keep things better encapsulated than the
MVC.
The Model, not only holds an instance of the Value Type (the object to be
editied), but it also holds a Current Selection and a Command Set. Instead
of relying on a UI to maintain a selection, the Model is notified via an
Interactor when a user makes a Gesture in the UI; the Current Selection can
vary from being a sub-list in the case of a multi-item object to just the
single object in the case of a basic ValueType like a string or integer.
When the Selection changes, the Command Set is notified and changes itself
to only allow Commands that are viable for the given Selection. In the case
of a list of objects, if the Selection is empty, then the Add Command is
enabled but the Insert, Delete, Edit, Cut and Copy Commands are disabled.
Changing the Selection to a single item will enable all Commands, while a
multiple selection will disable Edit and Insert.
The Command Set can be visualised in the UI by a popup context menu or maybe
a MS Money style 'what to do' bar.
The View is made to be an Observer of the Value Type held in the Model and
will respond to changes in the Value Type by updating itself to reflect the
current state of the object it is displaying.
The Presenter, which holds a reference to each of the Model and View, also
holds one or more Interactors.
An Interactor is essentially an object that has one or more event handlers
or delegates that are listening for changes in the UI (View). The Interactor
responds to a Gesture, by interpreting it into : a change in the Selection
or a sending of change of content in the edit to the Value Type. This
includes UI elements like radio groups or checkboxes that are used to
represent sets or boolean values
UI elements like buttons and menu items are not usually handled by an
Interactor, but are linked directly to a relevant Command; the OnClick event
handled directly in the associated Command and the button or menu item
enabled or disabled according to the state of the Command.
Now comes the bit that keeps the Model and View apart in terms of stopping
recursion.
Interactors can be enabled or disabled; they can enable or disable
themselves. Which means that if they instigate a change in the Value Type
that is known to propogate to a change in the UI, the Interactor can prevent
itself from receiving further notifications until the change has completed.
Interactors can also be nested and can propogate user input to other, more
sophisticated, Interactors to handle things like dragging an item from one
control to another or even to another application.
Ultimately, the MVP framework allows for the nesting of MVP 'Components' so
that each property of an object has its own MVP to link it to an
edit/checkbox/combo on a form and these are all contained and maintained
within an overall Presenter which links the object in the Model to the form.
Once the nested MVP framework is completed, it is then possible to write a
business class and design a form where each edit has the name of the
property it is to represent, but where there is absolutely no code on the
form itself. Then by simply instantiating a Presenter, passing the business
object to the constructor, a Model will be created for you, a View (form)
will be created for you, they will be linked together, all the properties
will have MVPs created for them and linked to the controls on the form via
Interactors; and finally the form will be shown and managed by the
Presenter.
Regardless of whether you want to achieve this level of sophistication in
your current situation, you at least need to implement some kind of
Controller to act as a Mediator between your Model and View, taking into
account the idea of enabling and disabling used in my Interactor classes.
If you are interested in further reading on MVP, then I have some articles
on my website
www.carterconsulting.org.uk, or you can Google in the news
groups for "joanna carter interactor" for more discussion on the finer
points on this part of the MVP which are not covered in the articles.
Joanna