创建仅在设计时、仅在运行时或运行时只读的属性

要创建在运行时可读,但只能在设计时设置的属性,可以用属性过程实现。在 Property Let 或 Property Set 过程中,检查 AmbientProperties 对象的 UserMode 属性。如果 UserMode 是 True,则产生一个错误,如下面的代码段所示:

Private mdblSerendipity As Double

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

Property Let Serendipity() As Double
   '(省略了验证属性值的代码。)
   If Ambient.UserMode Then 
   Err.Raise Number:=382 _
      Description:= _
      " Let/Set not supported at run time."
   End If
   Serendipity = mdblSerendipity
   PropertyChanged "Serendipity"
End Property

要在运行时完全禁止访问某个属性,可以在 Property Get 中产生“运行时属性不可用”错误。

注意 在实现 Variant 数据类型的属性时,需要全部的三个属性过程:Property Get、Property Let 和 Property Set,因为用户可以为此属性赋予包括对象引用在内的任何数据类型值。在这种情况下,Property Let 中产生的错误也必须在 Property Set 中产生。

与属性错误有关的错误值

下面的错误值是由 Visual Basic 提供的,应该被用于由只读和只写属性引起的错误:

Err.NumberErr.Description

382运行时不支持 Let/Set。

383设计时不支持 Let/Set。

393运行时不支持 Get。

394设计时不支持 Get。

如果某个属性是运行时只读的,而且 UserMode 为 True,那么在 Property Let 和 Property Set 过程中将发生错误 382。如果某个属性是运行时不可使用的,那么在 Let 和 Set 过程中将发生错误 382,而在 Get 过程中则发生错误 383。与此类似,如果某个属性是设计时不可使用的,那么在 Let 和 Set 过程中将发生错误 393,而在 Get 过程中则发生错误 394。在 ReadProperties 事件中处理运行时只读的属性

一般情况下,建议在 ReadProperties 事件中将获取的值赋予属性,从而调用 Property Let。这将允许 Property Let 中的验证代码处理用户手工输入到容器源文件中的无效值,请参阅“保存属性”。

显然,这对于运行时只读的属性是个问题。解决的办法是跳过 Property Let,把获取的值直接赋给私有成员或子控件属性。如果属性只接受特定的值,则可以设计辅助函数,供 Property Let 和 ReadProperties 调用。

以下代码说明了这两种方案:

Private Sub UserControl_ReadProperties(PropBag As _
      PropertyBag)
   '总是使用 ReadProperties 中的可捕获的错误!
   On Error Resume Next
   '获取 HasWidgets 属性的值,
   '它在运行时是只读的。
   mblnHasWidgets = _
      PropBag.ReadProperty("HasWidgets", False)
   If Err.Number <> 0 Then
      '如果 .frm 文件包含使类型
      '   不匹配的值(错误 13),则
      '   用缺省值替换属性。
      mblnHasWidgets = False
      ' When using On Error Resume Next, always
      '   reset Err.Number after an error.
      Err.Number = 0
   End If

   '获取 Appearance 属性的值,
   '可在设计时设置它,
   '并且有两个有效
   '值,Appears3D  AppearsFlat  (应在 Public Enum '定义这些常数。)
   mintAppearance = ValidateAppearance( _
      PropBag.ReadProperty("Appearance", Appears3D))
   '验证由 .frm 文件获取
   '   的值。
   Call ValidateAppearance(mintAppearance)
   If Err.Number <> 0 Then
      '如果 .frm 文件包含无效的
      '   整形值(错误 380)或使类型
      '   不匹配的值(错误 13),则
      '   用缺省值替换属性。
      mintAppearance = Appears3D
      '在使用 On Error Resume Next 时,总要
      '   在错误之后复位 Err.NumberErr.Number = 0
   End If

   ' . . . 其它属性 . . . 
End Sub

对于具有 Boolean、String 或一般的数字值类型属性,可以简单把值赋给私有成员,如上例中对 HasWidgets 属性那样处理。

Appearance 属性的 Property Let 将调用与上例相同的 ValidateAppearance 辅助函数,但不会捕获错误;于是,该错误将在指定了无效值的那个代码行出现。辅助函数看起来可能是这样的:

Private Sub ValidateAppearance(ByVal Test As Integer)
   Select Case Test
      Case Appears3D
      Case AppearsFlat
      Case Else
         '错误 380 是标准的“无效属性
         '   值”错误。
         Err.Raise 380
   End Select
End Sub

重点 如果在源文件中输入了错误的数据类型,则会发生类型不匹配错误。于是,甚至对布尔属性或数值属性也可能引起错误。(这就是应该在 ReadProperties 中使用错误捕获的原因。)可以用 On Error Resume Next 捕获此错误,如上所示,并用缺省值替换属性。

创建仅在运行时有效的属性

要创建仅在运行时可用的属性,可以使属性过程在设计时(即 AmbientProperties 对象的 UserMode 属性为 False 时)无效。

Visual Basic 的“属性”窗口不会显示在设计时无效的属性。

提示 可以打开“过程属性”对话框,选择仅在运行时有效的属性,然后单击“高级”按钮,并选择“在属性浏览器中不显示”,从而防止“属性”窗口询问该属性。这就避免因为“属性”窗口询问该属性而进入中断方式,在调试设计时的行为时,该方式是很讨厌的。