Welcome To The Home Of The Visual FoxPro Experts  
home. signup. forum. archives. search. google. articles. downloads. faq. members. weblogs. file info. rss. print.
MANAGER OF THE OBJECTS LINKED BY COMMON DATA

You can create a form and connect it with data. What could be easier? It's very easy, especially in Visual FoxPro. Furthermore, you can create many forms, good and different. Each of them, as a rule, displays the data of some table or, more often, several tables.

Is it possible that some forms display the same data? Certainly—this frequently the case. Besides, the forms can have private data sessions. If you load some such forms and make changes in one of them, you won't see the change in other forms until you've made them via some mouse or keyboard manipulations. The situation becomes even worse if you create and start classes distinct from forms. They can be invisible to you, and you can't get to them by mouse. What's the solution?

Someone should take command
Yes, "someone" should do it. In this case, there's some ambiguity, which can misinform you and lead to incorrect results. I've named this "someone" the Manager of Objects. It can exist during the entire operating time of the application, while there will be objects linked by common data. And so, I create an instance of the Manager, in this case as a public variable to make the example easier to follow:


PUBLIC goDLOM && where DLOM is Data Linked Objects Manager
goDLOM=CREATEOBJECT('DataLinkedObjectManager')

Now it's ready to command, but does the Manager know what objects work with the same data set? No, it doesn't. The Manager won't know anything about these objects if they don't declare anything about themselves. Each object, when it's created, should be registered in the Manager. It's most convenient to have this happen in the Init method of the created object:

PROCEDURE Init
	goDLOM.AddClient(THIS)
ENDPROC

When the Manager knows all the participants of the game, it can serve as the referee. How can it know what's taken place with one object or another? The Manager knows nothing about objects, and it can't determine what happens with them. An object can know only about itself.

In changing the data, the object should inform the Manager about it, and the Manager, in turn, must inform all other objects of this event, excepting the hero of the occasion. Usually, for this purpose I use the object's SomeControlLostFocus method and the object's DataSetIsChanged property, which confirms the real change of a data set.

PROCEDURE SomeControlLostFocus
	IF THIS.DataSetIsChanged
		* … updating code …
		goDLOM.UpdateAllClients(THIS)
	ENDIF
ENDPROC

Who will refresh the data?
It's high time to ask, "Can the Manager update the data of objects?" Each participant of the game should have its own method, which is named RefreshData, to update its data. In this method of an object, the logic of reception of the fresh data will be latent. Upon receiving the notification from an active object, the Manager will just need to call this method for all objects.

What happens if someone is too tired to play?
The objects don't exist eternally, and they're sometimes unloaded from memory. The Manager should be notified about such a sad fact. The object must do so itself, before it has died. The most suitable place for this to occur is in the Unload method of the object:

PROCEDURE Unload
	goDLOM.RemoveClient(THIS)
ENDPROC

How many nuts in a pocket?
If someone wants to find out the number of participants in the game, it can ask the Manager, using the NumberOfClients property.

Definition of a Manager class


Now that all of the conditions have been determined, it's time to generate the list of properties and methods of a Manager class (see Table 1).

Name of memberTypeDescriptionAddClientMethodAdds a new object to client list.NumberOfClientsPropertyGives the number of registered clients.RemoveClientMethodRemoves the specified object from the client list.UpdateAllClientsMethodUpdates the data sets of all registered clients.
Table 1. Properties and methods of the Manager class.

In my applications I use the following definition of the class:

*-- Class:             DataLinkedObjectManager
*-- ParentClass:       Custom
*-- BaseClass:         Custom

DEFINE CLASS DataLinkedObjectManager AS custom
 Name='DataLinkedObjectManager'
 
 ** The list of clients to be driven by this manager
 DECLARE CLIENTS(1)
 
 ** Number of registered clients
 NumberOfClients=0
 
   PROCEDURE NumberOfClients_access
     LOCAL lnNumberOfClients
     IF ALEN(THIS.Clients)=1 AND ISNULL(THIS.Clients(1))
       lnNumberOfClients=0
     ELSE
       lnNumberOfClients=ALEN(THIS.Clients)
     ENDIF
   RETURN lnNumberOfClients
   ENDPROC
 
   PROCEDURE NumberOfClients_assign
     LPARAMETERS vNewVal
     RETURN
   ENDPROC
   
   PROCEDURE Init
     THIS.Clients(1)=NULL
   ENDPROC
   
   PROCEDURE Release
     RELEASE THIS
   ENDPROC
   
   ** Adds a new client into client list
   PROCEDURE AddClient
     LPARAMETERS loReference
     IF THIS.NumberOfClients=0
       THIS.Clients(1)=loReference
     ELSE
       DIMENSION THIS.Clients(THIS.NumberOfClients+1)
       THIS.Clients(THIS.NumberOfClients)=loReference
     ENDIF
   ENDPROC
   
   ** Removes a specified client from client list
   PROCEDURE RemoveClient
     LPARAMETERS loReference
     LOCAL lnElement, llSuccess, lnIndex
     lnElement=0
     FOR lnIndex=1 to THIS.NumberOfClients
       IF THIS.Clients(lnIndex)=loReference
         lnElement=lnIndex
         EXIT
       ENDIF
     ENDFOR
     IF lnElement!=0
       IF THIS.NumberOfClients=1
         THIS.Clients(1)=NULL
       ELSE
         ADEL(THIS.Clients,lnElement)
         DIMENSION THIS.Clients(THIS.NumberOfClients-1)
       ENDIF
       llSuccess=.T.
     ELSE
       llSuccess=.F.
     ENDIF
     RETURN llSuccess
   ENDPROC  
   
   ** Updates data sets of all registered clients  
   PROCEDURE UpdateAllClients
     LPARAMETERS loPushingObject
     LOCAL loCurrentObject
     IF THIS.NumberOfClients > 0
       FOR EACH loCurrentObject IN THIS.Clients
         IF loCurrentObject != loPushingObject
           loCurrentObject.RefreshData()
         ENDIF
       ENDFOR
     ENDIF
   ENDPROC
   
ENDDEFINE

Conclusion
Most applications aren't limited to one data set. Therefore, for each such set it's possible to create an instance of the Manager class. Besides, some objects can be registered in several Managers, if their data crosses several data sets of the application.

Download code
You can download the class source code here. The download is a zipfile. Its size is 864 bytes.

This article was first published in the March, 2002 issue of FoxTalk.

ABOUT THE AUTHOR: VLADIMIR TRUKHIN

Vladimir Trukhin Vladimir Trukhin is Visual FoxPro developer and author. He has been developing program systems and applications since 1983. He specializes in software system development, user interface design, object oriented programming, developer support, training and other services. Vladimir has written for FoxTalk magazine. Visual FoxPro is his everyday tool and assistant. You can contact him by e-mail at vlt@votges.ru. You can find additional information about Vladimir on home page at http://www.geocities.com/vhpcg/resume.html.

FEEDBACK


Your Name: 
Your Feedback: 

Spam Protection:
Enter the code shown: