(c) Copyright 2000-2003, Dutch version, SDGN / Viafox, All rights reserved
(c) Copyright 2007, English version, Viafox, All rights reserved

The article 'Activating the Refresh' was originally published in the Dutch SDGN-Magazine nr. 57. This is a translated version that differs to some extend and is factually better.

Activating the Refresh

Copyright Viafox

Adequately refreshing objects is one of the more troublesome jobs of the VFP-programmer. 'Adequate' means here that it must be done in time and, moreover, only one time. An object's value or property should change under certain circumstances, but the practice is that at unexpected moments such an expected change does not always occur. Or that the change occurs more than one time. This many times refreshing often occurs in background and completely unnoticed. If lucky, the developer or user notices a performance drop, but that's not always the case. What goes wrong?

 

First a sketch of a typical programmer job.If I want to change an object's value or property one of the ways to do that is to put code in its Refresh method and to call such an object's Refresh method whenever the code needs to be processed. If more objects need an update, I might call some method of the container that contains the objects and let that method call the various Refresh methods.

It is crucial to choose the most appropriate place for those calls. And that's not always easy. A good programmer wants to prevent redundant code and will stick to certain 'paths'. Suppose you have a couple of checkboxes on the form and you want a refresh of the whole form in case any of those boxes is changed, then you might decide to handle all objects that need a refresh in each Click method, but it is a far better strategy to call one specific method in each of those Click methods and handle the refreshes in that single method.. It is possible that this single method too merely calls another method that does the refresh. That's why I used the word 'paths'. The called method might be a native method, but it can also be a user defined method.

 

Okay, back to the question: What goes wrong? Before giving the answer I'd like to explain another principle in VFP. Even if some central method calls the various Refresh methods, the implication is that each object that needs to be refreshed is called separately. Separate calls are handy only in case you need to refresh some specific objects. If all objects in a container need to be refreshed, simply call the Refresh method of that container and VFP will automatically refresh all its contained objects. An additional advantage is that removal or addition of other objects in that container are handled too without any need to change the code.

 

Okay, back again to the question: What goes wrong? Can we now answer it? No, not really, because there's another principle that must be explained also. It may be the case that you chose to place a pageframe on the form. The form itself is a container object. The keyword Thisform refers to this object. The pageframe gets, by default, the name Pageframe1 and is also a container. It contains pages which are also containers: Page1, Page2, et cetera. Each of them has its own Refresh method. But equally important is that Thisform and the various Pages have the methods Activate and Deactivate. These methods are called by VFP itself on various occasions. In other words, it are Events, so let's drop the word Method here. (Keep in mind that Refresh methods are NOT Events!) The Activate/Deactivate events are the ideal places for the programmer for manipulating the refreshes of the objects. Suppose theory says that all objects on all pages need a refresh when the user selects a new row in a grid that's on page 1. Does that imply that this must all be done immediately? Perhaps not, because what's the use of refreshing pages that are invisible so far? Refreshing them under all conditions might cause a serious drop in performance. This was also the idea of the developers of VFP at Microsoft, that's why a refresh of the Pageframe container will automatically refresh the active page, but not the other pages. But the consequence is that such an inactive page will quickly need to be refreshed the very moment the user activates that page. And that's where the Activate event comes in handy. Suppose the user clicks on page 3, then simply add Thisform.Pageframe1.Page3.Refresh (or better: This.Refresh) to the Activate method of page 3.

 

Okay, back again to the question: What goes wrong? Why are objects not always refreshed when we expect this to happen? Or why is that done too often? The answer is a limited or wrong understanding of the way that Refresh (is not an Event) and Activate (is an Event) have been implemented. It is not easy to fully understand these concepts and they are counter intuitive in some aspects. Read for example this part of the documentation: 'When a form is refreshed, all controls on the form are also refreshed. When a page frame is refreshed, only the active page is refreshed.' I have already explained what drove Microsoft here and I agree that speed is an issue, especially for VFP, but it is counter intuitive at least for the beginner. Another example: Page 2 is active, the user clicks outside the window (so outside the form). Next the user clicks in the window, but now on page 3. Activate and Deactivate are events, remember?! And VFP decides when they are visited. Here is the order, and it is not intuitive, at least for me: Page2.Activate, Thisform.Activate, Page2.Deactivate and finally Page3.Activate. Do you understand the reasoning?

Such counter intuitive principles are the cause of frequently or infrequently occuring unexpected behaviors. The programmer has put 'wrong' calls in 'wrong' methods and that's not clear to anyone who has a limited or wrong understanding of the concepts. Refreshes are done correctly most times, but not always, or they are done several times while one time is enough. The users will complain (or not!) and the programmer will most of the time do some patchwork only, thus degrading the quality of the code. (A typical scenario is that the user complains that object txtMsg is not refreshed if button A is clicked. So, the programmer goes to the Click method of button A and adds a line to its code: Thisform.txtMsg.Refresh. Problem solved and code degraded.) But perhaps the schemes in this article can be of use here!

 

The schemes are a working model. A working model does not necessarily reflect the whole theory. This working model must be helpful during programming. You can easily read in what order VFP will do the Refresh and visit the Activate/Deactivate events. Print the schemes, put them on your desk or hang them on a wall nearby. Whenever you feel doubt, take a look and you will feel more secure where refresh calls should be done.

 


The Refresh Model in Visual Foxpro

         VFP does not automatically start calling any Refresh method. This is also not done when it is creating the objects. It is also not done in the Init method of the form. It can only be done programmatically.

         Calling a Refresh Method automatically causes a call of all underlying Refresh methods.

 

 

This happens when calling the Refresh method of the Form

1.        Call of Refresh Methods of objects at the level of the Form, amongst them Pageframes;

2.        Only the Active Page of a Pageframe is refreshed;

3.        All Refresh Methods of the objects on the Active Page are refreshed.

 

This happens when calling the Refresh method of a Pageframe

1.        Only the Active Page of a Pageframe is refreshed;

2.        All Refresh Methods of the objects on the Active Page are refreshed.

 

When calling the Refresh method of a Page (active or inactive)

1.        Call of all Refresh methods of the objects on the Page (active or inactive).

 

When calling the Refresh method of a Container

1.        Call of the Refresh methods of the objects in the Container.


The Activate Model in Visual Foxpro

 

         VFP does not automatically start calling any Refresh method. So, this is also not done automatically from any Activate event. The two models are entirely separated. It is the programmer who must call Refresh methods from an Activate event.

         Programmatically calling a (De)Activate event does not automatically cause a call of underlying (De)Activate events.

 

 

When activating the Form by clicking outside the Pageframe or by clicking on an object in de Active Page (X) :

 


 

When activating the Form by clicking on an object in another Page (Y) :

 


 

 

If the focus is within the Form inside or outside the Pageframe, and then clicking on another Page (Y) :

 


 


If the focus is within the Form but outside the Pageframe, and then clicking on an object in the active Page (X) :

 


 

 

Home