ActiveX controls can't exist on their own. In order to function, they must be deposited into some other element of a running application, referred to as a container.
Often it is necessary to obtain information about or alter properties of the container. You can query the container in order to keep your control's properties in synch with the properties of its container; you can even alter certain properties of the container from your control.
A container can be a Visual Basic form, but it can also be any number of other things, including a Microsoft Access form, a Microsoft Excel spreadsheet, or a Web page displayed in Microsoft Internet Explorer. Other ActiveX controls can act as containers. AÊcontainer can also be an application you've never even heard of at the time you authored your ActiveX control.
You have to refrain from overly-ambitious assumptions about what your control's container can do, because the ActiveX specification sets out few hard-and-fast requirements for what containers can be expected to do.
You can use the container to provide a number of handy features for your control. However, failing to plan for the various implementations of ActiveX control containers can leave your control without a leg to stand on, so to speak.
The most commonly used container in a Visual Basic project is the form. Virtually every Visual Basic application has at least one form, and almost every form contains at least one control.
In addition, Visual Basic controls can contain other controls. For example, PictureBox controls are sometimes used solely as containers, without even utilizing their primary property, the Picture.
The Visual Basic Frame control can also be a container; it is most commonly used as a container for OptionButton controls, although you can use it as a container for your controls as well.
As the number of applications that use Visual Basic for Applications (VBA) increases, you'll find there are more and more places in which ActiveX controls can be found. Now that Microsoft has licensed VBA version 5.0 to third-party developers, you'll likely start seeing ActiveX controls popping up in unexpected places, such as Microsoft Office applications, Visio drawing documents, and Adobe Photoshop. This is because support for ActiveX control hosting is a feature of VBA 5.0. For more information on the applications in which ActiveX controls can be used today, see Chapter 2 "Control Basics."
For a demonstration of how to embed an ActiveX control in a non-VB
container (specifically, Microsoft Access) see Chapter 12.
TIP |
You can see a complete list of the companies that have licensed VBA 5.0, and are presumably going to adapt their applications to serve as ActiveX control hosts, on the Microsoft Web site, http://www.microsoft.com/vba/ vbawho.htm. |
Microsoft Internet Explorer's browser window is a container of its own, with its own effects on a control's behavior.
You use the Microsoft ActiveX control pad to embed an ActiveX control in a Web page. For more information on how to embed and program ActiveX controls in a Web page, see Chapter 13, "Using Your Control on the Web."
The Extender object is your primary interface with the container. The properties exposed by the Extender object are the way you gain information about the container and alter its properties (for those container properties that are allowed to be changed by controls they contain).
The Extender object becomes available when the InitProperties or ReadProperties event is raised in your UserControl. It is not available in your control's Initialize event.
For more information on events in the UserControl object, see Chapter 5 "Handling and Raising Events."
The Extender object of a container exposes a set of standard properties
described in Table 7.1.
Property | Description | Data Type | Availability |
Name | The name given to the control by the user (not the name of the container) | String | Read-only |
Visible | Specifies whether the control is visible | Boolean | Read-write |
Parent | An object that represents the control's container. You can get the name of the container (for example) by using the syntax Extender.Parent.Name | Object | Read-only |
Cancel | Specifies whether the control acts as the cancel button for the form; only used with command button-like controls | Boolean | Read-only |
Default | Specifies whether the control acts as the default button for the form; only used with command button-like controls | Boolean | Read-only |
In addition to the standard Extender properties described in the
preceding table, Visual Basic exposes an additional set of Extender
properties listed in Table 7.2.
Property | Description | Data Type | Availability |
Container | An object that represents the control's container. You can use this object to get additional properties of the container; for example, Extender.Container.Name will return the name of the container on which the control resides | Object | Read-only |
DragIcon | A Picture object; the icon displayed when the control is being dragged | Object | Read-write |
DragMode | Specifies manual or automatic drag-and-drop | Integer | Read-write |
Enabled | Specifies whether the control can be accessed as an element of the user interface. This property requires special implementation. | Boolean | Read-only |
Height | The height of the control | Integer | Read-write |
HelpContextID | The ID of the help topic that is displayed when the user requests online help and the focus is on the control | Integer | Read-write |
Index | The position this control occupies if it is in control array; if the control is not in an array, the property is not available | Integer | Read-write |
Left | The position of the control in terms of how far it is from the left edge of its container | Integer | Read-write |
TabIndex | The control's position in the tab order | Integer | Read-write |
TabStop | Determines whether the control takes the focus when the user presses Tab to change the focus from one control to the next | Boolean | Read-write |
Tag | A text string stored by the control and accessible in code | String | Read-write |
ToolTipText | Text that appears when the user positions the mouse on top of the control for one second | String | Read-write |
Top | The position of the control in terms of how far it is from the top edge of its container | Integer | Read-write |
WhatThisHelpID | The ID of the control's What's This pop-up help topic | Integer | Read-write |
Width | The width of the control | Integer | Read-write |
In addition to these properties, the Visual Basic Extender object provides the following standard methods:
All of these methods are similar to other standard methods you should be familiar with in Visual Basic controls.
The Enabled property is a special case, since it is technically a container-supplied property, but it doesn't function until you write code for it. This has to do with the fact that controls that provide the Enabled property have both runtime and design-time behaviors that need to be managed by the Visual Basic IDE.
The code to add an Enabled property to your control is fairly simple:
Public Property Get Enabled() As Boolean Enabled = UserControl.Enabled End Property Public Property Let Enabled(ByVal NewValue As Boolean) UserControl.Enabled = NewValue PropertyChanged "Enabled" End Property
The AmbientProperties object is another way for your control to interact with its container. You can inspect the properties of the AmbientProperties object to get cues about how your control's default properties should be set. You synchronize your control's properties with that of its container in your control's InitProperties event.
For example, to make the default BackColor of your control the same as the form on which it resides, you'd write the following code in your control's InitProperties event:
Private Sub UserControl_InitProperties() Debug.Print "InitProperties." BackColor = Ambient.BackColor End Sub
To test this code, switch to an EXE project form, change the form's BackColor property to some color other than the default, then place the control on the form. You should be able to see that the control is the same color as the form (as shown in Figure 7.1).
Figure 7.1 : The control is the same color as the form.
The control's AmbientProperties object is typically accessed through the use of the Ambient property of the UserControl. For example, to determine whether the control is in design mode or run mode, you might use the following code. Ambient properties are always read-only.
If Ambient.UserMode = True Then Label1.Caption = "Running." Else Label1.Caption = "Design mode." End If
Table 7.3 contains the complete list of ambient properties provided
through the Visual Basic AmbientProperties object.
Property | Description |
BackColor, ForeColor | Standard color properties |
DisplayAsDefault | Determines if the control is the container's default button |
DisplayName | Returns a string used as the name displayed in the control's error messages |
Font | Standard font property |
LocaleID | Used for internationalization purposes |
MessageReflect | Indicates whether the container can handle message reflection. This property is ignored in a Visual Basic ActiveX control |
Palette | Standard palette property |
RightToLeft | Determines the text input method on a bidirectional system |
ScaleUnits | A string that indicates the container's coordinate measurement system (such as points, pixels, or twips). This property is ignored in a Visual Basic ActiveX control. |
ShowGrabHandles | Indicates whether the control should display grab handles in design mode. This property envisions a container that handles control resizing in some custom manner unlike that of Visual Basic; consequently this property is ignored in a Visual Basic ActiveX control. |
ShowHatching | Indicates whether the control should display hatching around its edges when it is in design mode in a container designed to accommodate hatching. Visual Basic does not support design-mode hatching, but Microsoft Access, for example, does. Consequently, this property is ignored in a Visual Basic ActiveX control. |
SupportsMnemonics | Indicates that the container supports access keys. This property is ignored in a Visual Basic ActiveX control. |
TextAlign | Indicates the manner in which the container would like the control to align text. Values are 0 (general alignment), 1 (left), 2 (center), 3 (right), 4 (fill justify). |
UIDead | Indicates whether the control should respond to user input. This property is ignored in a Visual Basic ActiveX control. |
UserMode | Indicates whether the control is in a container that is in run mode (True) or design mode (False) |
The AmbientChanged event of the UserControl enables your control to keep up with changes in the container's properties. For example, you might want the background color of your control to always be the same as the background color of its container. To do this, you write code in the AmbientChanged event to make the BackColor property of your control the same as the ambient BackColor property. To see how to use the AmbientChanged event, do the following:
Private Sub UserControl_AmbientChanged(PropertyName As String) Debug.Print "AmbientChanged: " & PropertyName BackColor = Ambient.BackColor End Sub
The Containerator project exists on the CD-ROM that accompanies this book. This project is designed to test which container-provided properties are available in a container.
The Containerator control is comprised of a single text box. The control exposes one custom method, ShowContainerProperties. This method displays a list of the container properties accessible by the control.
To build this control, do the following:
Listing 7.1 The Containerator Control
Public Sub ShowContainerProperties() ' sticks info on container properties into ' txtInfo. On Error Resume Next ' very important txtInfo.Text = txtInfo.Text & "*Cancel: " & Extender.Cancel & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "*Cancel: Not available." & vbCrLf Err.Clear End If ' Container is an object, so use its Name txtInfo.Text = txtInfo.Text & "Container: "_ & Extender.Container.Name & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "Container: Not available." & vbCrLf Err.Clear End If txtInfo.Text = txtInfo.Text & "*Default: " & Extender.Default & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "*Default: Not available." & vbCrLf Err.Clear End If ' DragIcon can't be displayed textually txtInfo.Text = txtInfo.Text & "DragMode: " & Extender.DragMode & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "DragMode: Not available." & vbCrLf Err.Clear End If ' Enabled requires some special fiddling around txtInfo.Text = txtInfo.Text & "Enabled: " & Extender.Enabled & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "Enabled: Not available." & vbCrLf Err.Clear End If txtInfo.Text = txtInfo.Text & "Height: " & Extender.Height & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "Height: Not available." & vbCrLf Err.Clear End If txtInfo.Text = txtInfo.Text & "Index: " & Extender.Index & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "Index: Not available." & vbCrLf Err.Clear End If txtInfo.Text = txtInfo.Text & "HelpContextID: "_ & Extender.HelpContextID & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "HelpContextID: Not available."_ & vbCrLf Err.Clear End If txtInfo.Text = txtInfo.Text & "Left: " & Extender.Left & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "Left: Not available." & vbCrLf Err.Clear End If txtInfo.Text = txtInfo.Text & "*Name: " & Extender.Name & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "*Name: Not available." & vbCrLf Err.Clear End If ' Parent is actually an object, so you have to get its Name txtInfo.Text = txtInfo.Text & "*Parent: " & Extender.Parent.Name_ & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "*Parent: Not available." & vbCrLf Err.Clear End If txtInfo.Text = txtInfo.Text & "TabIndex: " & Extender.TabIndex & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "TabIndex: Not available." & vbCrLf Err.Clear End If txtInfo.Text = txtInfo.Text & "Tag: " & Extender.Tag & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "Tag: Not available." & vbCrLf Err.Clear End If txtInfo.Text = txtInfo.Text & "TabStop: " & Extender.TabStop & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "TabStop: Not available." & vbCrLf Err.Clear End If txtInfo.Text = txtInfo.Text & "ToolTipText: " & Extender.ToolTipText_ & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "ToolTipText: Not available." & vbCrLf Err.Clear End If txtInfo.Text = txtInfo.Text & "Top: " & Extender.Top & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "Top: Not available." & vbCrLf Err.Clear End If txtInfo.Text = txtInfo.Text & "*Visible: " & Extender.Visible & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "*Visible: Not available." & vbCrLf Err.Clear End If txtInfo.Text = txtInfo.Text & "WhatsThisHelpID: "_ & Extender.WhatsThisHelpID & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "WhatsThisHelpID: Not available."_ & vbCrLf Err.Clear End If txtInfo.Text = txtInfo.Text & "Width: " & Extender.Width & vbCrLf If Err Then txtInfo.Text = txtInfo.Text & "Width: Not available." & vbCrLf Err.Clear End If End Sub
Containerator1.ShowContainerProperties
There's a bunch of code in the Containerator control, but it all does pretty much the same thing: tests the properties of the Extender object to see if they're available. The code uses error-trapping to keep from crashing the host application in the (very likely) case where a particular property of the Extender object isn't available. For more information on error-trapping in a control, see Chapter 15, "Debugging and Error Trapping."
To test the Containerator control, drop it into an EXE project form and add a command button to the form. In the command button's Click event, write the code:
Containerator1.ShowContainerProperties
Run the EXE project, then click on the command button to execute the ShowContainerProperties method. Your form should display something similar to Figure 7.2.
Figure 7.2 : Testing the Containerator.
The Container property of a control is not to be confused with the concept of the container. Visual Basic provides the Container property so you can change the container that a control is associated with.
For example, consider a form that contains three controls: two PictureBoxes and a Label control contained in the first PictureBox. You could cause the Label to jump from the first PictureBox to the second by writing the code:
Label1.Container = PictureBox2
The Container property doesn't have a direct bearing on control creation, although there's no reason why you couldn't build a control to take advantage of this property. (This property existed in versions of Visual Basic prior to version 5.0.) Hopefully with this short explanation of this property you won't furrow your brow, as I did, when you run across it in online Help.
In this chapter, you learned about the properties of the Visual Basic container and how non-Visual Basic containers differ from Visual Basic forms. We covered ambient properties supplied by the container, as well as using the Extender object as a way to interact with the container.
In the next chapter, you'll explore the concept of constituent controls in depth, putting together what you've learned in the last few chapters into one big mega-control of doom.