Visual Basic Concepts

How to Handle Focus in Your Control

The way you handle focus for your control depends on which model you're using to develop your control. Models for building ActiveX controls are discussed in "Three Ways to Build ActiveX Controls," earlier in this chapter.

*Important* If you're authoring a control that can be a container for other controls, as described in "Allowing Developers to Put Controls on Your Control," note that the material in this topic does not apply to controls a developer places on an instance of your control. These contained controls will receive focus independent of your control and its constituent controls.

User-Drawn Controls

If you're authoring a user-drawn control, there won't be any constituent controls on your UserControl. If you don't want your control to be able to receive the focus, set the CanGetFocus property of the UserControl object to False. CanGetFocus is True by default.

If your user-drawn control can receive the focus, the UserControl object will receive GotFocus and LostFocus events when your control receives and loses the focus. A user-drawn control is responsible for drawing its own focus rectangle when it has the focus, as described in "User-Drawn Controls," in this chapter.

This is the only function your UserControl's GotFocus and LostFocus events need to fulfill for a user-drawn control. You don't need to raise GotFocus or LostFocus events for the user of your control, because the container's extender provides these events if the CanGetFocus property is True.

*Note* The UserControl object of a user-drawn control will also receive a EnterFocus event prior to GotFocus, and an ExitFocus event after LostFocus. You don't need to put any code in the event procedures of these event, and in fact it is recommended that you not do so.

User-drawn controls can respond to access keys, as described later in this topic.

Controls That Use Constituent Controls

If you're authoring a control that enhances a single constituent control, or is an assembly of constituent controls, your UserControl object will be unable to receive the focus, regardless of the setting of the CanGetFocus property, unless none of its constituent controls can receive the focus.

If no constituent controls can receive the focus, and CanGetFocus is True, then your UserControl object will receive the same events a user-drawn control receives. The only thing you need to do with these events is provide a visual indication that your control has the focus.

How Constituent Controls Are Affected by CanGetFocus

If your control contains at least one constituent control that can receive the focus, the CanGetFocus property of the UserControl object must be set to True. If you attempt to set CanGetFocus to False on a UserControl that has constituent controls that can receive focus, an error will occur.

Visual Basic will not allow a constituent control that can receive focus to be placed on a UserControl whose CanGetFocus property is False: Icons of controls that can receive focus are disabled in the Toolbox when the UserControl's design window is active.

EnterFocus and ExitFocus

When the focus moves from outside your control to any of your control's constituent controls, the UserControl object will receive an EnterFocus event. The GotFocus event for the constituent control that receives the focus will be raised after the UserControl_EnterFocus event procedure.

As long as the focus remains within your control, the UserControl object's focus-related events will not be raised. As the focus moves from one constituent control to another, however, the appropriate GotFocus and LostFocus events of the constituent controls will be raised.

When the focus moves back outside your control, the last constituent control that had the focus will receive its LostFocus event. When the event procedure returns, the UserControl object will receive its ExitFocus event.

You can use the EnterFocus event to change which constituent control receives the focus. You may wish to do this in order to restore the focus to the constituent control that last had it, rather than simply allowing the first constituent control in your UserControl's tab order to receive the focus, which is the default behavior.

*Tip* If your control is complex — as for example an Address control with multiple constituent controls — you may be tempted to validate the data in the ExitFocus event. Don't. The user of your control can put code in the Validate event of the user control to handle data validation as they see fit. If it's absolutely necessary to validate data inside the control, use the Validate events in combination with the CausesValidation properties of the constituent controls. Be aware that you can't always count on the Validate event for constituent controls, as is discussed in "Handling the Validate Event" below.

*Tip* Generally speaking, it's not a good idea to use MsgBox when you're debugging focus-related events, because the message box immediately grabs the focus. It's a very bad idea to use MsgBox in EnterFocus and ExitFocus events. Use Debug.Print instead.

Receiving Focus via Access Keys

Avoid hard coding access keys for your control's constituent controls, because access keys permanently assigned to your control in this fashion will limit a user's freedom to choose access keys for her form. In addition, two instances of your control on the same form will have access key conflicts.

"Allowing Developers to Set Access Keys for Your Control," later in this chapter, discusses how you can give the user of your control the ability to set access keys on instances of your control.

Forwarding Focus to the Next Control in the Tab Order

If your control cannot receive the focus itself, and has no constituent controls that can receive the focus, you can give your control the same behavior displayed by Label controls. That is, when the access key for your control is pressed, the focus is forwarded to the next control in the tab order.

To enable this behavior, set the ForwardFocus property of the UserControl object to True.

Handling the Validate Event

The Validate event and CausesValidation property for a user control behave exactly like they do for any other control, but the behavior of Validate and CausesValidation for constituent controls may not yield the expected results. Let's review the standard behavior. When a control loses focus, its Validation event is fired before its LostFocus event — but only if the control about to receive the focus has its CausesValidation property set to True. This allows you to handle data validation before the control loses focus.

A user control exposes a Validate event and, via the Extender object, exposes a CausesValidation property. Code in the Validate event is executed when the focus is shifted from the user control to any control that had its CausesValidation property set to True; setting the CausesValidation property of the user control to True will enable the Validation event for any control passing focus to the user control.

The Validate event and CausesValidation property for constituent controls work as expected as long as the focus remains inside the user control. When the focus is shifted outside of the user control, the Validate event for the constituent control isn't fired. For that reason, it's best to avoid trying to handle validation within a user control.