Creating Design-Time-Only, Run-Time-Only, or Read-Only Run-Time Properties

See Also

To create a property that can be read at run time, but can be set only at design time, implement the property using property procedures. In the Property Let or Property Set procedure, test the UserMode property of the AmbientProperties object. If UserMode is True, raise an error, as shown in the following code fragment:

Private mdblSerendipity As Double

Property Get Serendipity() As Double
   Serendipity = mdblSerendipity
End Property

Property Let Serendipity() As Double
   ' (Code to validate property values omitted.)
   If Ambient.UserMode Then 
      Err.Raise Number:=382 _
         Description:= _
         "Let/Set not supported at run time."
   End If
   Serendipity = mdblSerendipity
   PropertyChanged "Serendipity"
End Property

To suppress a property completely at run time, you can also raise a "Property is not available at run time" error in Property Get.

Note   Implementing properties of the Variant data type requires all three property procedures, Property Get, Property Let, and Property Set, because the user can assign any data type, including object references, to the property. In that case, the error raised in Property Let must also be raised in Property Set.

Error Values to Use for Property Errors

The following error values are provided by Visual Basic and should be used when raising errors for read-only or write-only properties:

Err.Number Err.Description
382 Let/Set not supported at run time.
383 Let/Set not supported at design time.
393 Get not supported at run time.
394 Get not supported at design time.

If a property is read-only at run time and UserMode is True, raise error 382 in the Property Let or Property Set procedure. If a property is not available at run time, raise error 382 in the Let or Set procedure and error 383 in the Get procedure. Likewise, if a property is not available at design time, raise error 393 in the Let or Set procedure and error 394 in the Get procedure.

Handling Read-Only Run-Time Properties in the ReadProperties Event

The recommended practice for the ReadProperties event is to assign the retrieved value to the property, so that the Property Let is invoked. This allows the validation code in the Property Let to handle invalid values the user has manually entered into the container's source file, as described in "Saving the Properties of Your Control."

Clearly, this is problematic for read-only run-time properties. The solution is to bypass the Property Let, and assign the retrieved value directly to the private member or constituent control property. If the property accepts only certain values, you can use a helper function that can be called from both Property Let and ReadProperties.

The following code fragment illustrates these two solutions:

Private Sub UserControl_ReadProperties(PropBag As _
      PropertyBag)
   ' Always use error trapping in ReadProperties!
   On Error Resume Next
   ' Retrieve the value of the HasWidgets property,
   ' which is read-only at run time.
   mblnHasWidgets = _
      PropBag.ReadProperty("HasWidgets", False)
   If Err.Number <> 0 Then
      ' If the .frm file contained a value that caused
      '   a type mismatch (error 13), substitute the
      '   default value for the property.
      mblnHasWidgets = False
      ' When using On Error Resume Next, always
      '   reset Err.Number after an error.
      Err.Number = 0
   End If

   ' Retrieve the value of the Appearance property,
   ' which can be set at design time
   ' and has two valid values, Appears3D
   ' and AppearsFlat.  (These constants should be 
   ' defined in a Public Enum.)
   mintAppearance = _
      PropBag.ReadProperty("Appearance", Appears3D)
   ' Validate the value retrieved from the .frm
   '   file.
   Call ValidateAppearance(mintAppearance)
   If Err.Number <> 0 Then
      ' If the .frm file contained an invalid integer
      '   value (error 380) or a value that caused a
      '   type mismatch (error 13), substitute the
      '   default value for the property.
      mintAppearance = Appears3D
      ' When using On Error Resume Next, always
      '   reset Err.Number after an error.
      Err.Number = 0
   End If

   ' . . . more properties . . .
End Sub

The Property Let for the Appearance property would call the same ValidateAppearance helper function used in the example above, but would not trap errors — thus the error would be raised at the line of code that assigned the invalid value. The helper function might look something like this:

Private Sub ValidateAppearance(ByVal Test As Integer)
   Select Case Test
      Case Appears3D
      Case AppearsFlat
      Case Else
         ' Error 380 is the standard "Invalid property
         '   value" error.
         Err.Raise 380
   End Select
End Sub

Important   If the wrong data type is entered in the source file, a type mismatch error will occur. Thus, errors can occur even for a Boolean or numeric property. (This is why you should always use error trapping in ReadProperties.) You can trap the error with On Error Resume Next, as above, and substitute the default value for the property.

Creating Run-Time-Only Properties

You can create a property that is available only at run time by causing property procedures to fail during design time (that is, when the UserMode property of the AmbientProperties object is False).

Visual Basic's Properties window does not display properties that fail during design-time.

Tip   You can open the Procedure Attributes dialog box, select your run-time-only property, click the Advanced button, and check "Don't show in Property Browser" to prevent the Properties window from interrogating the property. This keeps the Properties window from putting you in break mode every time it queries the property, which is a nuisance when you're debugging design-time behavior.