Understanding Control Lifetime and Key Events

See Also

Designing ActiveX controls involves a radical shift in perspective. The key events you must respond to are different — for example, your life will revolve around the Resize event — and there's no such thing as QueryUnload. But that's just the beginning.

"Control Creation Terminology," earlier in this chapter, introduced the idea that a control is not a permanent fixture of a form. Indeed, design-time and run-time instances of your control will be created and destroyed constantly — when forms are opened and closed, and when you run the project.

Each time an instance of your ActiveX control is created or destroyed, the UserControl object it's based on is created or destroyed, along with all of its constituent controls. ("The UserControl Object," earlier in this chapter, explains the basis of all ActiveX controls created with Visual Basic.)

Consider, for example, a day in the life of the ShapeLabel control used in the step-by-step procedures in "Creating an ActiveX Control."

  1. The user creates an instance of ShapeLabel — by double-clicking on the Toolbox, or by opening a form on which an instance of ShapeLabel was previously placed.

  2. The constituent controls, a Shape and a Label, are created.

  3. The UserControl object is created, and the Shape and Label controls are sited on it.

  4. The UserControl_Initialize event procedure executes.

  5. The ShapeLabel control is sited on the form.

  6. If the user is placing a new ShapeLabel, the InitProperties event of the UserControl object occurs, and the control's default property values are set. If an existing form is being opened, the ReadProperties event occurs instead, and the control retrieves its saved property values.

  7. The UserControl_Resize event procedure executes, and the constituent controls are resized according to the size the user made the new control instance, or the size they were before the form was closed.

  8. The Show and Paint events occur. If there are no constituent controls, the UserControl object draws itself.

  9. The user presses f5 to run the project. Visual Basic closes the form.

  10. The UserControl object's WriteProperties event occurs, and the control's property values are saved to the in-memory copy of the .frm file.

  11. The control is unsited.

  12. The UserControl object's Terminate event occurs.

  13. The UserControl object and its constituent controls are destroyed.

And that's not the half of it. The run-time instance of the form is now created, along with a run-time instance of the ShapeLabel control. When the user closes the form and returns to design mode, the ShapeLabel is destroyed and re-created once again.

The rest of this topic explains the key events in a UserControl object's life, and provides reference lists of the events you receive in several important scenarios.

Key UserControl Events

The meanings of the key events in the life of a UserControl object are as follows:

In addition to the events listed above, the Show and Hide events may be important to your control. Show and Hide occur as indicated in Figure 9.5.

Figure 9.5   Show and Hide Events

In order to draw to the screen in Windows, any control must have a window, temporarily or permanently. Visual Basic ActiveX controls have permanent windows. Before a control has been sited on a form, its window is not on the container. The UserControl object receives Show and Hide events when the window is added and removed.

While the control's window is on the form, the UserControl receives a Hide event when the control's Visible property changes to False, and a Show event when it changes to True.

The UserControl object does not receive Hide and Show events if the form is hidden and then shown again, or if the form is minimized and then restored. The control's window remains on the form during these operations, and its Visible property doesn't change.

If the control is being shown in an internet browser, a Hide event occurs when the page is moved to the history list, and a Show event occurs if the user returns to the page.

Note   If your control is used with earlier versions of Visual Basic, the UserControl object will not receive Show and Hide events at design time. This is because earlier versions of Visual Basic did not put any visible windows on a form at design time.

For More Information   The topic "Life and Times of a UserControl Object," one of the step-by-step procedures in "Creating an ActiveX Control," demonstrates the key events in the life of a control and illustrates how often control instances are created and destroyed.

The Incarnation and Reincarnation of a Control Instance

Let's follow a control instance from its placement on a form, through subsequent development sessions, until it's compiled into an application. We'll assume the control was already developed and compiled into an .ocx file, before the curtain opens.

The scenarios that follow mention both Resize and Paint events. Which event you're interested in depends on the control creation model you're using, as discussed in "Three Ways to Build ActiveX Controls," earlier in this chapter.

If your control provides its appearance using constituent controls, you'll use the Resize event to size the constituent controls. If you're authoring a user-drawn control, on the other hand, you can ignore the Resize event and remarks about constituent controls. User-drawn controls draw their appearance in the Paint event. This is discussed in "Drawing Your Control," later in this chapter.

Note   In all of these scenarios, the order and number of Resize and Paint events may vary.

The Control Instance is Placed on a Form

When you double-click a control's icon in the Toolbox, a design-time instance of the control is placed on the form you're designing. The following events occur in the UserControl object at the heart of the control instance:

Event What gets done
Initialize Constituent controls have been created, but the control has not been sited on the form.
InitProperties The control instance sets default values for its properties. The control has been sited, so the Extender and AmbientProperties objects are available. This is the only time the instance will ever get this event.
Resize, Paint The control instance adjusts the size of its constituent controls, if any, according to its default property settings. A user-drawn control draws itself.

The developer of the form can now see the control, and set its properties in the Properties window. After the developer does this, she may press f5 to run the project.

From Design Mode to Run Mode

When F5 is pressed, the control's design-time instance on the form is destroyed. When the form is loaded at run time, the control is recreated as a run-time instance.

Event What gets done
WriteProperties Before the design-time instance is destroyed, it has a chance to save property values to the in-memory copy of the .frm file.
Terminate Constituent controls still exist, but the design-time control instance is no longer sited on the form. It's about to be destroyed.
Initialize Constituent controls have been created, but the run-time control instance has not been sited on the form.
ReadProperties The control instance reads the property values that were saved in the in-memory .frm file. The control has been sited on the run-time instance of the form, so the Extender and AmbientProperties objects are available.
Resize, Paint The control instance adjusts the size of its constituent controls, if any, according to its current property settings. A user-drawn control draws itself.

The developer tests the form by clicking the control, or taking other actions that cause the control's properties, methods, and events to be exercised.

From Run Mode to Design Mode

Finally the developer closes the form and returns to design mode. The run-time instance of the control is destroyed, and a design-time instance is created:

Event What gets done
Terminate The run-time instance never gets a chance to save property settings. Changes to property values while the program was running are discarded.
Initialize Design-time instances of constituent controls have been created, but the design-time control instance has not been sited on the form.
ReadProperties The control reads the property values that were saved in the in-memory copy of the .frm file. The control has been sited on the design-time instance of the form, so the Extender and AmbientProperties objects are available.
Resize, Paint The control instance adjusts the size of its constituent controls, if any, according to its saved property settings. A user-drawn control draws itself.

Closing the Form

If the developer doesn't need to work on the form any more, she may close it. Or it may be quitting time, and she may close the whole project. In either case, the control instance on the form is destroyed.

Event What gets done
WriteProperties Before the design-time instance is destroyed, it has a chance to save property values to the in-memory copy of the .frm file.
Terminate Constituent controls still exist, but the control instance is no longer sited on the form. It's about to be destroyed.

Note   In all of the scenarios above, the control instance has been saving its property values to the in-memory copy of the .frm file. If the developer chooses not to save the project before closing it, those property settings will be discarded.

Additional Scenarios

When the developer re-opens the project, and opens the form to work on it again, the control is reincarnated as a design-time instance. It receives Initialize, ReadProperties, Resize, Paint, and WriteProperties events.

Note   A WriteProperties event? Yes, indeed. When the project is opened, Visual Basic creates an in-memory copy of the .frm file. As each control on the form is created, it gets a ReadProperties event to obtain its saved property values from the .frm file, and a WriteProperties event to write those property values to the in-memory copy of the .frm file.

Compiling the Project

When the project is compiled into an application or component, Visual Basic loads all the form files invisibly, one after another, in order to write the information they contain into the compiled file. A control instance gets the Initialize, ReadProperties, and WriteProperties events. The control's property settings are compiled into the finished executable.

Running the Compiled Program or Component

Whenever a user runs the installed application or component, and the form is loaded, the control receives Initialize, ReadProperties, and Resize events. When the form is unloaded, the control receives a Terminate event.

Controls on World Wide Web Pages

A control on an HTML page is specified using the HTML <OBJECT> and </OBJECT> tags. When the HTML is processed, the control is created and positioned. If the <OBJECT> tag includes any <PARAM NAME> attributes, the property values supplied with those attributes are passed to the control's ReadProperties event using the standard PropertyBag object, as discussed earlier in this topic.

Once the HTML page is active, the control's property values may also be set by scripts attached to events that occur on the page.

Note   If there are no <PARAM NAME> attributes other than those that set extender properties, the control may receive an InitProperties event rather than a ReadProperties event. This behavior is dependent on browser implementation, and should not be relied on.

Events You Won't Get in a UserControl object

Some events you're familiar with from working with forms don't exist in a UserControl object. For example, there is no Activate or Deactivate event, because controls are not activated and deactivated the way forms are.

More striking is the absence of the familiar Load, Unload, and QueryUnload events. Load and Unload simply don't fit the UserControl lifestyle; unlike a form, a control instance isn't loaded at some point after it's created — when a UserControl object's Initialize event occurs, constituent controls have already been created.

The UserControl object's Initialize and ReadProperties events provide the functionality of a form's Load event. The main difference between the two is that when the Initialize event occurs, the control has not been sited on its container, so the container's Extender and AmbientProperties objects are not available. The control has been sited when ReadProperties occurs.

Note   ReadProperties doesn't occur the first time a control instance is placed on a container — in that case the InitProperties occurs instead.

The UserControl event most like a form's Unload event is Terminate. The constituent controls still exist at this point, although you no longer have access to the container, because your control has been unsited.

The WriteProperties event cannot be used as an analog of Unload, because it occurs only at design time.

UserControl objects don't have QueryUnload events because controls are just parts of a form; it's not up to a control to decide whether or not the form that contains it should close. A control's duty is to destroy itself when it's told to.

Events Peculiar to UserControls

The GotFocus and LostFocus events of the UserControl object notify user-drawn controls when they should show or stop showing a focus rectangle. These events should not be forwarded to the user of your control, because the container is responsible for focus events.

If your UserControl has constituent controls that can receive focus, the EnterFocus event will occur when the first constituent control receives the focus, and the ExitFocus event will occur when focus leaves the last constituent control. See "How to Handle Focus in your Control," later in this chapter.

If you have allowed developers to set access keys for your control, the AccessKeyPress event occurs whenever a user presses an access key. See "Allowing Developers to Set Access Keys for Your Control," later in this chapter. The AccessKeyPress event can also occur if your control is a default button or cancel button. This is discussed in "Allowing Your Control to be a Default or Cancel Button," later in this chapter.

The AmbientChanged event occurs whenever an Ambient property changes on the container your control has been placed on. See "Using the AmbientProperties Object to Stay Consistent with the Container," later in this chapter.