[AccessD] Building a control class

John W Colby jwcolby at gmail.com
Thu Mar 12 16:38:55 CDT 2009


AD,

 >In your view, what could be the best strategy for projecting the 
events pertaining to form object variable in form class, into the 
control class ?

In general a control class should not be aware of the form and 
particularly its events.  If the form needs to have a control do 
something in response to one of the form's events, you should expose a 
method in the control class to call from the form's event.  Let's take 
an example:

I use a combo control to cause the form to select a record.  The form 
and the combo should "stay in sync" or it is visually confusing.  IOW, 
if the form moves to a specific record, the record selector combo should 
"move to" and display that same record.  Obviously if the combo selects 
a record, the form should move to that record.  The form and combo "stay 
in sync".

I created a "mSyncToForm(lngPKID)" method in the combo class.  In the 
form's Current event the clsCboRecSel.mSyncToForm is called passing in 
the form's PKID.  The combo class then causes the combo control to 
display the record with that value in column 0.  Thus the combo "syncs" 
to the form.

OTOH, if the user selects a record that they want to move to, the form 
should move to that record.  clsCboRecSel defines an Event 
evAfterUpdate(lngPKID as long).  The clsCboRecSel raises the 
'evAfterUpdate event in the combo's AfterUpdate event stub in the 
class.  clsCboRecSel is declared Withevents back in the form.  An event 
stub is created in clsFrm sinking evAfterUpdate.  When evAfterUpdate 
fires, control passes back to the form's evAfterUpdate event stub and 
the form has to grab a copy of the RecordsetClone, move to that record, 
grab the bookmark, then set the form's bookmark to that bookmark, 
causing the form to move to the right place.

Notice that the clsCboRecSel doesn't need to know anything about the 
form in either case.  It can sync to the form simply by exposing a 
method for the form to call, and the form can sync to the record 
selector simply by sinking an event raised by the record selector class.

So the answer is to build functionality into the control class, and 
expose that functionality via methods of the control class.  Raise 
events in the control class as required to notify the form that the 
control class did something that the form class might want to know about.

Often times the control class behaviors simply don't matter to the 
form.  For example my combo control wrapper class can be programmed to 
open a specific list form in the dbl-click event so that the list behind 
the form can be programmed.  The form that carries the combo control 
doesn't care about that, in fact that is a behavior that might be useful 
in any combo in any form.  It is the combo control classes' business, 
not the form class' business.

IMO classes really need to *try* to be independent of each other.  
Sometimes it is not possible, sometimes specific sets of classes form a 
system and need each other to perform the whole task.  On the other hand 
even when they might need to know about each other, you should try to 
use an interface - an exposed method or raising an event - to allow the 
partner object to get something done.  Programming an interface helps to 
disentangle the objects themselves.

 >If a WithEvents variable of form type is declared in control class and 
is set equal to the form variable belonging to form class, it hampers 
proper closing.

Yes, it definitely can.  a circular reference is formed where the form 
refers to the form class which refers to the control class and the 
control class refers to the form.  The answer is being rigorous in your 
cleanup.  Sometimes just setting the pointer to the control class to 
nothing back in the form class is enough to cause the control class to 
close properly.  The class terminate MUST set pointers to all objects to 
nothing.  If the terminate event fires then the form pointer is cleaned 
up as is the pointer to the wrapped control(s).  If this cleanup is not 
performed then things start to break.  Occasionally I have had to expose 
a mTerm() method that I explicitly called back in the parent class 
before setting the pointer to the child class to nothing.  That mTerm 
class performs all of the cleanup.  The Class_Terminate() event then 
calls mTerm in cases where the pointer in the parent is just set to nothing.

Cleanup is CRITICAL.  If you do cleanup correctly, then it is quite 
possible to grab pointers to the form, and even sink form events.  
Sinking form events can be risky though in the earlier versions of 
Access, and can cause page faults in weird situations.

 >On the other hand, if a custom event is raised in form object's event 
(say current event) in form class, thereby enabling setting up of 
WithEvents object of form class type (set equal to the form class) in 
the control class, the said event does come up in the intellisense but 
does not show any activity.

The event should fire in the control class, as long as the event 
property is set to [Event Property].  I have done so before and it does 
work.  It is not clear whether you intend for the clsFrm to raise an 
event and be sunk in the control class, or for the form itself to have 
an event sunk in the control class.  Either one *should* work.  I have 
never tried to sink an event raised by my clsFrm inside of a control 
class, nor have I even declared clsFrm Withevents in a control class.


I have to say I am heartened to have you asking so many questions about 
classes and events.  From your general Access knowledge level I long ago 
assumed that you were probably way above me in this stuff.  From the way 
you study stuff I assume that you soon will be anyway.  ;)


John W. Colby
www.ColbyConsulting.com



A.D.Tejpal wrote:
> John,
>
>     Thanks for clarifying the points raised in earlier posts.
>
>     In your view, what could be the best strategy for projecting the events pertaining to form object variable in form class, into the control class ?
>
>     If a WithEvents variable of form type is declared in control class and is set equal to the form variable belonging to form class, it hampers proper closing. Similar is the case if it is set equal to parent of  the incoming control argument.
>
>     On the other hand, if a custom event is raised in form object's event (say current event) in form class, thereby enabling setting up of WithEvents object of form class type (set equal to the form class) in the control class, the said event does come up in the intellisense but does not show any activity.
>
> Best wishes,
> A.D. Tejpal
> ------------
>   



More information about the AccessD mailing list