Share via


Visual Basic Concepts

How Property Pages Work

Property pages look a lot like forms, and designing them is somewhat similar to designing forms. The way property pages work, however, is quite different from the way forms work.

For example, when the Property Pages dialog box creates an instance of a property page, the Initialize event is the first event the PropertyPage object gets — just as it would be for a form. However, unlike a form, the PropertyPage object doesn’t get a Load event. The key event for PropertyPage objects is the SelectionChanged event.

This topic examines the three things your PropertyPage object must do:

  • In the SelectionChanged event, obtain the property values to be edited.

  • Set the PropertyPage object’s Changed property whenever the user edits a property value.

  • In the ApplyChanges event, copy the edited property values back to the selected control (or controls).

The SelectionChanged Event

The SelectionChanged event occurs when the property page is displayed, and when the list of currently selected controls changes.

For example, after selecting an instance of your control and opening the Property Pages dialog box, a developer might realize that she needed to change the properties of two instances of your control. By clicking the second instance while holding down the CTRL key, she could add the second instance to the list of selected controls. Each of your property pages would then receive a SelectionChanged event.

Important   You should always treat the SelectionChanged event as if your property page is being loaded for the first time. As you’ll see, changing the selection fundamentally changes the state of the property page.

Coding the SelectionChanged Event for a Single Control

The most important thing you need to do in the SelectionChanged event is to set the values of the controls that display property values for editing. For example, consider the General page for the VirtualVelociraptor control (originally shown in Figure 10.1):

Suppose that the Age property of the VirtualVelociraptor control uses the following public Enum:

Public Enum DinoAge
   vvHatchling
   vvJuvenile
   vvAdult
End Enum

The SelectionChanged event of the property page might look like this:

Private Sub PropertyPage_SelectionChanged()
   ' Place the value of the DinoName property for the
   '   first selected control in the txtDinoName text
   '   box for display and editing.
   txtDinoName = SelectedControls(0).DinoName
   ' Use the value of the Age property of the first
   '   selected control to select the appropriate
   '   option button in the Age frame.
   optAge(SelectedControls(0).Age).Value = True
   ' (The code above depends on the fact that the
   '   elements of the DinoAge Enum have the values
   '   0, 1, and 2.)
End Sub

Tip   The Property Page Wizard will populate your property page with text box controls and check boxes (for Boolean properties), and generate default code for the SelectionChanged event.

The SelectedControls Collection

The SelectedControls collection contains all the controls currently selected in the container the developer is working on. The collection may contain several instances of your control; if the property page is shared by more than one control in your control component, the collection may contain controls of multiple types.

Note   You don’t need to worry about the collection containing controls other than your own — text boxes, for example — because the Property Pages dialog box only displays those pages that are used by all of the currently selected controls.

For the moment, ignore the possibility that multiple controls might be selected. What the code in the SelectionChanged event shown above is doing is taking the value of each property for the first control in the collection and assigning it to the appropriate control on the property page.

In the case of a single selected control, this places all of the control’s property values in fields where the user can edit them.

Different Ways to Edit Properties

Instead of showing the property value of the Age property as a set of option buttons, you could use a drop-down list showing the elements of the enumeration:

The drop-down list takes up less space than the option buttons did (an advantage that grows larger as the number of possible values increases), and it shows the names of the constants that would be used in code.

The following code fragment shows how you might set up such a list.

Private Sub PropertyPage_SelectionChanged()
   txtDinoName = SelectedControls(0).DinoName
   ' Create a drop-down list containing the values and
   '   names of the Enum elements for the Age
   '   property, and select the one that corresponds
   '   to the current value of the Age property.
   cboAge.AddItem vvHatchling & " - vvHatchling"
   cboAge.AddItem vvJuvenile & " - vvJuvenile"
   cboAge.AddItem vvAdult & " - vvAdult"
   cboAge.ListIndex = SelectedControls(0).Age
   ' (The index of each Enum element in the drop-down
   '   list is the same as the element's value.)
End Sub

Tip   While you can choose any editable representation that makes sense for a property, remember that the more space each property takes up, the more tabs you’ll need. Minimizing the number of tabs makes the property pages for your control easier to use. For most enumerations, a drop-down list will make the most efficient use of space.

Coding the SelectionChanged Event for Multiple Controls

To determine whether multiple controls are selected, you can test the Count property of the SelectedControls collection to see whether it’s greater than one.

In order to deal with multiple selected control instances, it’s useful to divide the properties of your control into two groups:

  • Properties that can sensibly be set to the same value for multiple controls. For example, it’s very convenient to be able to set the BackColor property of several Label controls to the same value.

  • Properties that do not make sense to set to the same value for multiple controls. For example, it’s not particularly helpful to set the Caption property of several Label controls to the same value. In fact, it might be quite annoying to the user to do so by accident.

One approach you might take in your SelectionChanged event is to disable the edit fields for properties of the second sort whenever multiple controls are selected. In the discussion of the ApplyChanges event, an alternate technique will be shown.

Shared Property Pages

If you have multiple controls in your project, and two such controls share a property page, make sure that you provide error trapping for the code that reads the property values. If the first control selected doesn’t include all of the properties shown on the page, an error will occur when you try to read that property value.

Enabling the Apply Button by Setting Changed = True

In order to tell Visual Basic that the user has edited one or more properties on a property page, you must set the PropertyPage object’s Changed property to True. Because there’s no way to know which property a user might decide to change, you must do this for every property displayed on the page.

For example, to notify the PropertyPage of changes in the DinoName or Age properties from the previous example, you would use the following code:

Private Sub txtDinoName_Changed()
   Changed = True
End

Private Sub cboAge_Change()
   Changed = True
End

Note that this is exactly the same as coding PropertyPage.Changed = True.

Notifying the PropertyPage object that values have changed enables the Apply button on the Property Pages dialog box, and causes the ApplyChanges event to occur when the Apply button is pressed, when the user changes tabs, or when the dialog box is dismissed.

Note   You may wish to keep track of which properties have changed, so that you don’t have to write them all out.

The ApplyChanges Event

The second most important event in a PropertyPage object is the ApplyChanges event. In this event you copy the edited property values back to the currently selected controls.

The ApplyChanges event occurs when the user:

  • Clicks the OK button to dismiss the dialog.

  • Clicks the Apply button.

  • Selects another tab in the Property Pages dialog box.

The following code for the ApplyChanges event assumes that the SelectionChanged event was coded using a drop-down list for the Age property, as shown earlier.

Private Sub PropertyPage_ApplyChanges()
   Dim vv As VirtualVelociraptor
   ' Set the DinoName property of the FIRST selected
   '   control only.
   SelectedControls(0).DinoName = txtDinoName

   For Each vv In SelectedControls
      ' Transfer the value currently selected in the
      '   drop-down list for the DinoAge property to
      '   all of the selected controls.
      vv.DinoAge = cboAge.ListIndex
      ' (The code above works because the value of
      '   each of the three elements of the Enum is
      '   the same as its index number in cboAge.)
   Next
End Sub

Because it generally doesn’t make sense to give all of the virtual velociraptors the same name, the DinoName property is applied only to the first selected control. The Age property, on the other hand, is applied to all the selected controls.

Note   As the control author, it’s up to you to decide which properties make sense to set for multiple selected controls.

Dealing with Errors in ApplyChanges

In the case shown above, there’s no chance of error in the ApplyChanges event. The text property is a simple string, and the drop-down list limits user input for the Age property to only those values that are valid.

If your property page allows the user to enter values that may be rejected by the Property Let (or Property Set) procedure, you should use error trapping in the ApplyChanges event. The simplest scheme is to use On Error Resume Next, and test Err.Number after each property that may raise an error.

When an error occurs:

  • Stop processing the ApplyChanges event.

  • Display an error message, so the user understands what went wrong.

  • Set the focus to the property that caused the error.

  • Set the Changed property of the PropertyPage object to True.

Important*   Setting Changed = True performs two functions. First, it re-enables the Apply button. Second, it prevents the Property Pages dialog box from being dismissed if the user clicked OK. *This is the only way to prevent the dialog box from closing.