Chapter 7

Interacting With the Container


CONTENTS

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.

What Is a Container?

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.

Visual Basic Containers

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.

Interacting with Non-VB Containers

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.

Using Microsoft Internet Explorer as a Container

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."

Using the Extender Object

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."

Properties Exposed by the Visual Basic Extender Object

The Extender object of a container exposes a set of standard properties described in Table 7.1.

Table 7.1 Standard Extender properties

PropertyDescription Data TypeAvailability
NameThe name given to the control by the user (not the name of the container) StringRead-only
VisibleSpecifies whether the control is visible BooleanRead-write
ParentAn object that represents the control's container. You can get the name of the container (for example) by using the syntax Extender.Parent.Name ObjectRead-only
CancelSpecifies whether the control acts as the cancel button for the form; only used with command button-like controls BooleanRead-only
DefaultSpecifies whether the control acts as the default button for the form; only used with command button-like controls BooleanRead-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.

Table 7.2 Additional VB Extender properties

PropertyDescription Data TypeAvailability
ContainerAn 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 ObjectRead-only
DragIconA Picture object; the icon displayed when the control is being dragged ObjectRead-write
DragModeSpecifies manual or automatic drag-and-drop IntegerRead-write
EnabledSpecifies whether the control can be accessed as an element of the user interface. This property requires special implementation. BooleanRead-only
HeightThe height of the control IntegerRead-write
HelpContextIDThe ID of the help topic that is displayed when the user requests online help and the focus is on the control IntegerRead-write
IndexThe position this control occupies if it is in control array; if the control is not in an array, the property is not available IntegerRead-write
LeftThe position of the control in terms of how far it is from the left edge of its container IntegerRead-write
TabIndexThe control's position in the tab order IntegerRead-write
TabStopDetermines whether the control takes the focus when the user presses Tab to change the focus from one control to the next BooleanRead-write
TagA text string stored by the control and accessible in code StringRead-write
ToolTipTextText that appears when the user positions the mouse on top of the control for one second StringRead-write
TopThe position of the control in terms of how far it is from the top edge of its container IntegerRead-write
WhatThisHelpID  The ID of the control's What's This pop-up help topic IntegerRead-write
WidthThe width of the control IntegerRead-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.

Providing an Enabled Property

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

Using the AmbientProperties Object to Synchronize Properties

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.

Table 7.3 Properties of the AmbientProperties object

PropertyDescription
BackColor, ForeColorStandard color properties
DisplayAsDefaultDetermines if the control is the container's default button
DisplayNameReturns a string used as the name displayed in the control's error messages
FontStandard font property
LocaleIDUsed for internationalization purposes
MessageReflectIndicates whether the container can handle message reflection. This property is ignored in a Visual Basic ActiveX control
PaletteStandard palette property
RightToLeftDetermines the text input method on a bidirectional system
ScaleUnitsA 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.
ShowGrabHandlesIndicates 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.
ShowHatchingIndicates 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.
SupportsMnemonicsIndicates that the container supports access keys. This property is ignored in a Visual Basic ActiveX control.
TextAlignIndicates 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).
UIDeadIndicates whether the control should respond to user input. This property is ignored in a Visual Basic ActiveX control.
UserModeIndicates whether the control is in a container that is in run mode (True) or design mode (False)

Using the AmbientChanged Event

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:

  1. Create a new control project. Add the following code to the UserControl:
Private Sub UserControl_AmbientChanged(PropertyName As String)
    Debug.Print "AmbientChanged: " & PropertyName
    BackColor = Ambient.BackColor
End Sub
  1. Close the code window and the control designer, then switch to the EXE test form. Add the control to an EXE project form.
  2. Using the Properties window, change the BackColor property of the EXE project form. The background color of the UserControl will change to match the color you selected.

Using Extender Properties with the Containerator Project

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:

  1. Start a new control project. Give the UserControl the name Containerator.
  2. Place a text box on the control designer. Make the text box about the same size as the designer.
  3. Give the text box the name txtInfo, set its Text property to nothing, and set its MultiLine property to True.
  4. Double-click on the control designer to open its code window. Enter the code in Listing 7.1.

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

  1. Close the code window and close the control designer.
  2. Switch to the EXE test form. Place an instance of the Containerator on the EXE test form.
  3. Run the EXE test project by choosing the menu commands Run, Start (or by using the function key F5).
  4. The project runs. Pause the project by selecting the menu command Run, Break, or by using the keystroke shortcut Ctrl+Break.
  5. The EXE project pauses. In the Immediate window, type the code:
Containerator1.ShowContainerProperties
  1. The Containerator displays a list of Extender properties it was able to retrieve.

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

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.

Summary

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.