[AccessD] Framework pseudo-definition

John Bartow john at winhaven.net
Thu Mar 25 21:22:44 CST 2004


Thanks for the confirmation.

And then AEIEIEE! Slap myself in the head! I thought you had said you were
"going" to do that but I never checked the files as I am following it by
reading only. It is a ROYAL PITA to cut them all apart and paste them into
word - thanks no more of that then. The first day I printed them out I just
highlighted all of the emails messages and hit print. Outlook proceeded to
print about 100 pages of your dialog at the beginning with Robert and
Stuart - but that was all, it just kept printing it over and over and of
course I didn't check until I got to the waiting room. Lucky I had my Pocket
PC synced with my outlook. Not as easy tor ead but better than Glamour ;o)

Oh yeah, wrapping my mind around this stuff is cool. I think to myself
sometimes that you must go into a deep trance to come up with some of it. I
just find myself thinking WOW!

Shamil's DEEP programming is the correct term for sure! I'm sure it builds
on itself and that seems to be how you arrived where you are. Makes me
wonder too, how many dead ends have you hit on this road?

Thanks again,
John B.

-----Original Message-----
From: accessd-bounces at databaseadvisors.com
[mailto:accessd-bounces at databaseadvisors.com]On Behalf Of John W. Colby
Sent: Thursday, March 25, 2004 9:02 PM
To: Access Developers discussion and problem solving
Subject: RE: [AccessD] Framework pseudo-definition


Data aware control.

Good to see someone reading this with that level of concentration.  BTW,
each of these lectures is a word doc in the zip files on my site.



John W. Colby
www.ColbyConsulting.com

-----Original Message-----
From: accessd-bounces at databaseadvisors.com
[mailto:accessd-bounces at databaseadvisors.com]On Behalf Of John Bartow
Sent: Thursday, March 25, 2004 9:32 PM
To: Access Developers discussion and problem solving
Subject: RE: [AccessD] Framework pseudo-definition


John,
Been reading these really close as I cut&paste them into Word and printed
them out (sitting in the clinic/hospital waiting room the couple of days and
had to have something to read other than People and Glamour).

So - I'm not trying to be nit picky here or anything just need to clarify a
question. If you scroll down and find the series of ??? in the text the
question is there.

John B.

-----Original Message-----
From: accessd-bounces at databaseadvisors.com
[mailto:accessd-bounces at databaseadvisors.com]On Behalf Of John W. Colby
Sent: Wednesday, March 03, 2004 9:05 PM
To: AccessD
Subject: [AccessD] Framework pseudo-definition


Folks,

I have thrown out suggestions about how I handle things "using my
framework".  Robert has asked me what a framework is and how to start one.
Unfortunately the word Framework is used by different people for different
things, so I will state my own definitions with the warning that I have no
intention of arguing with anyone who doesn't like my definition.

For my purposes, a framework is a skeleton.  Look at a skyscraper being
built on the horizon.  The framework is all that steel, the elevators, the
air conditioning, electrical service, water, sewage etc.  ALL of that stuff
is necessary regardless of whether you intend to rent one thousand square
feet or one million.  And once all of that stuff is in place, the rest is
just sheetrock, aluminum framing, doors and windows.

My framework starts with a class named dclsFW, the framework class.  It is
instantiated ONE time (a single instance), but inside of that class is the
foundation of the rest of the system.  It has "class global" variables for
other "service" classes.  By "class global" I mean private to the class (can
only be directly manipulated by the class) but global to the class (can be
seen from anywhere in THAT class).  By Service classes I mean classes such
as my SysVars, Zip/unzip, Encrypt/Decrypt and so forth.  These are really
"standalone classes", they do not require my framework at all in order to
function, but by placing then in my framework class I provide them to any
other part of my class.  dclsFW instantiates all these service classes when
dclsFW initializes, and tears them down when dclsFW terminates.  dclsFW also
provides property gets to allow other code to access these service classes
directly.

ALL classes, EVERY SINGLE ONE, have a set of common stuff at the top, a
handful of private constants and variables, and init/term events.  This
stuff is SO common that you can literally cut and paste it from a "template
class" into a new class and save that and have a new working class.

The framework class dclsFW is just the foundation of the framework, it is
NOT the skeleton itself.  Because Access is so Form-centric I have an entire
skeleton for forms and controls.  Thus I have a form class named dclsFrm.
This class is instantiated by any form that wants to use my framework (90%
or more in my databases) in the form's OnOpen.  Each form has a "form
global" (dimensioned PUBLIC) variable for the dclsFrm, and instantiates it
in OnOpen, then calls the init of dclsFrm passing in a pointer to itself.
dclsFrm then stores that pointer to the form in a private variable in it's
header.

dclsFrm is the foundation of the FORM skeleton if you will, but it uses
services provided by dclsFW (the framework foundation class).  dclsFrm also
SINKS EVERY form event.  The private form variable in dclsFrm's header is
dimensioned WithEvents and I then built event stubs for every single form
event.  The ONLY one that doesn't actually function is OnOpen and that is
because the class is instantiated in the form's built-in class in OnOpen and
therefore by the time dclsFrm loads OnOpen has come and gone.  One
implication of this is that NO FORM is lightweight since it must have its
built-in class to store the pointer to my dclsFrm, and of course an OnOpen
to set and initialize dclsFrm.

Just as we have a class for the form, EVERY data aware control has a class
which I name dclsCtlCbo, dclsCtlTxt, dclsCtlGrp etc. mostly so that all of
the control classes will group together in the module window, but also
because it makes it obvious that these classes are control classes.  dclsFrm
has a private function called from its Init() which I call FindControls
(very descriptive I know).  This function iterates the form's Control
Collection.  Remember that dclsFrm was passed a pointer to the form by the
form itself as it initialized dclsFrm.  As I iterate the control collection
I have a large case statement that basically says:

for each ctl in frm.controls
	select case ctl.ControlType
	case "textbox"
		'instantiate the text box control class
	case "combo"
		'instantiate the combo class
	etc
	end select
next ctl

Thus as each control is examined I discover the type of the control, I load
an instance of the class for that type of control and pass in a pointer to
the control.  I save all of these control classes into a collection.  By the
time FindControls is finished I have loaded a class instance for EVERY
control on the form (more or less), and each of those control class
instances has a pointer to it's control.  As I do in the form, I dim the
control variable in each control class Withevents and build event sinks for
the control events.  In this case I am a little more lenient and only build
event sinks for the events I actually use.  I did this partly because I
don't use many of the key events and mouse events (in every control) and
didn't want the overhead of those event stubs being called all the time.

Now this sounds like a LOT of work, and a LOT of overhead.  It is a lot of
work, but in fact very little overhead.  It turns out that classes load the
entire class ONE TIME, then only a new header section (global variables) for
each additional instance of that class type.  Thus if I load 10 combo class
instances, only one loads completely, then just the header of the other 9.
All of the code is shared... unless there are static variables in the
functions which is handled appropriately such that each class instance has
it's own static variables.  I ran some timing awhile back on a VERY complex
form with dozens of controls.  What I discovered is that on an old 100 mhz
Pentium of the day, the overhead was one half of one millisecond per class
instance, to load each instance.  Folks, that is NOTHING compared to the
time to load the data for example.  And of course that was a sloooooowwwwww
computer compared to what we have now.

So there you have it.  By the time dclsFrm loads, it also loads a class for
each data aware class on the form.

????????????????????????????????????????????????????????
Is the sentence abov suppose to read this way or is it supposed to be:
By the time dclsFrm loads, it also loads a class for each data aware
"control" on the form.
????????????????????????????????????????????????????????

The form's skeleton is built and loaded.

Now that I have classes for each control and the form, and these classes
sinking all the necessary events, I can add functionality to each class as
desired.  All of the various things you have heard me discuss in the "in my
framework I do..." emails are nothing more than discovering the code
required to do this stuff, then putting it out in the classes in the
framework.

Let's take a working example.  Every data aware control may be referenced by
a combo, list or subform in the SQL statement or query that loads the data
into these objects.  Thus a combo can be "filtered" by another combo, or by
a check box, or by a text box etc.  I call the object being filtered a
"dependent object" because its dataset depends on some other control (or
controls).  In ALL of my classes for data aware controls I have a collection
which I call colDepObjs.  So every combo, list, textbox, checkbox etc. class
has this collection.  It also has a function which allows me to pass in to
the class a list of controls that are dependent on that control, i.e. whose
data is filtered by that control.  A pointer to these controls (or their
class actually) are stored in colDepObjs.  Each class also has a public
RequeryDepObjs method which can be called.  This method... you guessed it...
iterates the dependent object collection and calls the requery method of
every class in the collection.  Thus is 3 combos are dependent on ComboA,
calling ComboA.RequeryDependentObjects causes requery ,method of the class
for comboB, ComboC, and ComboD.  The requery method requeries the actual
control (combo or list etc) but also calls its own RequeryDependentObjects
method which ... calls the Requery method of any classes in its colDepObj.

In order to use this functionality, all I have to do is call a function of a
class passing in pointers to the controls that are dependent on this
control.  Now, when ComboA AfterUpdate fires (remember I sink the events in
the control classes) the AfterUpdate calls it's RequeryDependentObjects
which starts the ball rolling requerying all dependent objects down the
chain.

One of the things that has been critical to efficiently handling all this
stuff is my framework SysVar table.  In my SysVar table I can turn on/off
functionality for the entire framework (all forms for example) or for a
specific service.  As an example I have a sysvar that says "turn on the
ZIP/Unzip service classes.  I leave them turned off under normal
circumstances.  However if a specific application needs zip/unzip
functionality, I can OVERRIDE the Sysvar by reading framework sysvars out of
a table in the FE.  Thus for that FE I can turn on/off the zip/unzip service
classes, and having done so, I can now just call a property of the framework
to get the zip class, call a method and zip up a file.

Likewise I can turn on / off a form behavior for a specific application.  I
can also override form behaviors on a form by form basis so that one form
has the behavior while the next does not.

Doing things this way allows me to tailor the framework for a specific
application, even down to tailoring it for specific forms.

I hope this email has started you thinking about frameworks, how you would
use them and what you would do with them.  If you ever take the time to
build one you will never look back.  Frameworks are an awesome tool that
takes an already RAD environment (Access) and allows you to plop down a
skeleton on which you build your app.  Imagine being able to tell the client
"I can build your skyscraper in 1/10th the time because I already have the
skeleton done".  Just add walls and windows and move in next week.  (Ok,
next month).  We all know that the data design is a critical piece which I
have not addressed here at all, but once that part is done, building forms
should be much more standardized than the way many developers do it.

I am going to stop here to allow anyone to ask questions, or other
developers who have their own frameworks to pipe in with "this is what I
do".

John W. Colby
www.ColbyConsulting.com


--
_______________________________________________
AccessD mailing list
AccessD at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/accessd
Website: http://www.databaseadvisors.com



--
_______________________________________________
AccessD mailing list
AccessD at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/accessd
Website: http://www.databaseadvisors.com



--
_______________________________________________
AccessD mailing list
AccessD at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/accessd
Website: http://www.databaseadvisors.com






More information about the AccessD mailing list