> Anyone deliberately implementing an MVC pattern in V16? Comments on
> trade-offs in
> a 4D-specific implementation?
I have. Unfortunately I haven’t had the time recently to contribute much on the
topic, but I am finding the pattern nice in a lot of ways. Without much detail,
here is how I’ve implemented it:
- Model: I have a UIModel module which handles throwing all kinds of things in
to the model (just a C_Object). This includes variables of all types, records,
etc. It is set up in such a way that I can ask the model if anything has
changed which is helpful when a window is closed. Normally a window has one
UIModel, but it is possible to have more.
- View: When a “view” is set up, I run a bit of code for each object. The
object might already exist on a form. If it doesn’t it is created (OBJECT
DUPLICATE) automatically from an inherited window which has an object for each
type. Part of setting up an object is binding it to a key in the UIModel. There
is a bunch of generic code for each object type that runs as needed, updating a
view object when the model changes and visa-versa. It also handles things like
keystrokes as the user enters data, etc.
- Controller: Each window has a controller method that binds things together.
This is where the model is set up, where view objects are set up, etc. It is
also called whenever the value or status of an object changes. Most things are
handled generically, so there isn’t often much code here, but it can trap for
pretty much anything and handle it in a customized way when needed.
One of the things I love about this is that I can have pretty complex UI
objects with almost zero code. Only the code that needs to set up the UI object
in the first place is necessary and that is declarative code (which I prefer).
Take a combo-box for example. In the set up I simply tell it that the UI object
should be a combo box and give it a name. Then I tell it that it should be
bound to some key in the model which can be a longint or text value. Then I
tell it what the possible choices are (for listing) and an associated value for
each (either long or text). For example, I might give it 10 values, each with a
UUID and a label. Obviously these come from passing in two arrays. But they can
be local arrays because they are stored in an object. So the method that
creates the combo box object only temporarily sets up the possible choices and
we aren’t using a process array. Once that is done, the user gets some goodies
like type-ahead, etc. for free. In the background, the UIModel is automatically
updated without any specific code on my part.
Anyway, it makes setting up a basic window really fast.
One of the things I don’t like about it is that I often need to bind values
from within an object to UI objects. For now I have to move them out of a
object and into a model as separate steps. If I was starting over I’d make sure
I could let the UIModel know that a key’s value maps to a key in some other
object.
I’ve actually tried to include window layout in all this by declaratively
coding where an object should be using a language like this:
UILayout_SetHortPosition ("Parent(L)<-(L)TablesSubform")
UILayout_SetVertPosition ("Parent(T)<-(T)TablesSubform”)
This would pin the upper left of the TablesSubform to the upper left of the
parent (probably the window, but things can be nested). The code can move
things around based on the needed object size (which can automatically change
based on the text within it). The code can even figure out the minimum size of
a window based on everything in the window. This is great for localization, for
example. However, I’m definitely pushing 4D’s boundaries at this point.
Sometimes I love it and sometimes I … don't.
Here’s another example:
UILayout_SetHortPosition ("FieldsListbox(|)->(|)FieldsSearchField")
UILayout_SetVertPosition ("FieldsSearchField(B)<-[-]-(T)FieldsListbox")
UILayout_SetWidthByDirect ("FieldsListbox";300)
UILayout_SetHeightByAnchor ("FieldsListbox(B)-[-30]->(B)Parent")
Anyway, I’m still experimenting with MVC and a new paradigm with layout out
objects on a window. Some things I like and some things I don’t. I wish I had
time to give more detail, but I’m rather behind on my projects right now….
Tip: Place a few hidden variables types as C_Objects on a window that is
inherited by other windows. I have one with the objects named UIModel, UIView,
UILayout, and UITimer with no variable associated with them. By default, the
UIModel module (and, I’m sure you can guess, other modules) will use these form
objects to store their information so I’m not using a process variable and to
keep the code more generic, even with multiple windows in a process. (But make
sure you make these variables fairly big, like 200 px x 200 px. Even though
they are invisible, there is a bug in 4D which makes things _really_ slow if
the actual C_Object variables on the form are too small!)
--
Cannon Smith
Synergy Farm Solutions Inc.
Hill Spring, AB Canada
403-626-3236
<[email protected]>
<www.synergyfarmsolutions.com>
**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ: http://lists.4d.com/faqnug.html
Archive: http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub: mailto:[email protected]
**********************************************************************