自定义控件的设计时属性(Windows 窗体 .NET)

本文介绍如何在 Visual Studio 的 Windows 窗体视觉对象设计器中为控件处理属性。

每个控件从基类 System.Windows.Forms.Control 继承许多属性,例如:

创建控件时,可以定义新属性并控制它们在设计器中的显示方式。

定义属性

具有由控件定义的 get 访问器的任何公共属性都会在 Visual Studio 属性窗口中自动显示。 如果该属性还定义了 set 访问器,则可以在“属性”窗口中更改该属性。 但是,可以通过应用 BrowsableAttribute,在”属性”窗口中显式显示或隐藏属性。 此属性采用单个布尔参数来指示是否显示它。 有关属性的详细信息,请参阅属性 (C#)属性概述 (Visual Basic)

[Browsable(false)]
public bool IsSelected { get; set; }
<Browsable(False)>
Public Property IsSelected As Boolean

[注意] 无法与字符串之间隐式转换的复杂属性需要类型转换器。

序列化属性

控件上设置的属性将序列化为设计器的代码隐藏文件。 当属性的值设置为默认值以外的其他值时,将发生这种情况。

当设计器检测到对属性的更改时,它将计算控件的所有属性,并序列化其值与该属性的默认值不匹配的任何属性。 属性的值序列化为设计器的代码隐藏文件。 默认值可帮助设计器确定应序列化哪些属性值。

默认值

当属性应用 DefaultValueAttribute 特性或属性的类包含属性特定的 ResetShouldSerialize 方法时,该属性被视为具有默认值。 有关属性的详细信息,请参阅特性 (C#)特性概述 (Visual Basic)

通过设置默认值,可以启用以下内容:

  • 如果已将属性的值修改为非默认值,则该属性会在“属性”窗口中提供视觉指示。
  • 用户可以右键单击该属性,然后选择“重置”,将属性还原为其默认值
  • 设计器生成更高效的代码。

如果属性使用简单类型(如基元类型),则可以通过将默认值应用于 DefaultValueAttribute 属性来设置。 但是,具有此特性的属性不会自动以该赋值开头。 必须将属性的支持字段设置为相同的默认值。 可以在声明或类的构造函数中设置属性。

当属性是复杂类型,或者想要控制设计器的重置和序列化行为时,请定义类的 Reset<PropertyName>ShouldSerialize<PropertyName> 方法。 例如,如果控件定义 Age 属性,则方法命名为 ResetAgeShouldSerializeAge

重要

应用 DefaultValueAttribute 到属性,或提供 Reset<PropertyName>ShouldSerialize<PropertyName> 方法。 不要同时使用这两者。

可以右键单击属性名称并选择“重置”,通过“属性” 窗口将属性“重置”为默认值。

属性网格中的“重置上下文”菜单项。

在以下情况下启用“属性”>右键单击>“重置”上下文菜单选项的可用性:

  • 该属性应用了 DefaultValueAttribute 特性,并且属性的值与特性的值不匹配。
  • 该属性的类定义没有 ShouldSerialize<PropertyName>Reset<PropertyName> 方法。
  • 该属性的类定义 Reset<PropertyName> 方法,并且 ShouldSerialize<PropertyName> 返回 true。

DefaultValueAttribute

如果属性的值与 DefaultValueAttribute 提供的值不匹配,则属性视为已更改,但可通过“属性”窗口重置。

重要

此特性不应该用于具有相应 Reset<PropertyName>ShouldSerialize<PropertyName> 方法的属性。

以下代码声明两个属性:默认值为 North 的枚举和默认值为 10 的整数。

[DefaultValue(typeof(Directions), "North")]
public Directions PointerDirection { get; set; } = Directions.North;

[DefaultValue(10)]
public int DistanceInFeet { get; set; } = 10;
<DefaultValue(GetType(Directions), "North")>
Public Property PointerDirection As Directions = Directions.North

<DefaultValue(10)>
Public Property DistanceInFeet As Integer = 10

重置和 ShouldSerialize

如前所述,Reset<PropertyName>ShouldSerialize<PropertyName> 方法不仅可用于指导属性重置行为,还可用于确定值是否已更改以及应序列化为设计器的代码隐藏文件。 这两种方法协同工作,不应定义一种而不定义另一种。

重要

不应为具有 DefaultValueAttribute 的属性创建 Reset<PropertyName>ShouldSerialize<PropertyName> 方法。

定义 Reset<PropertyName> 时,“属性”窗口显示该属性的“重置”上下文菜单选项。 选择“重置”时,将调用 Reset<PropertyName> 方法。 “重置”上下文菜单选项由 ShouldSerialize<PropertyName> 方法返回的内容启用或禁用。 当 ShouldSerialize<PropertyName> 返回 true 时,它指示属性已从其默认值更改,应序列化为代码隐藏文件,并启用“重置”上下文菜单选项。 返回 false 时,将禁用“重置”上下文菜单选项,并且代码隐藏已删除属性集代码。

提示

这两种方法都可以且应该使用专用范围进行定义,以便它们不会构成控件的公共 API。

以下代码片段声明一个名为 Direction 的属性。 此属性的设计器行为由 ResetDirectionShouldSerializeDirection 方法控制。

public Directions Direction { get; set; } = Directions.None;

private void ResetDirection() =>
    Direction = Directions.None;

private bool ShouldSerializeDirection() =>
    Direction != Directions.None;
Public Property Direction As Directions = Directions.None

Private Sub ResetDirection()
    Direction = Directions.None
End Sub

Private Function ShouldSerializeDirection() As Boolean
    Return Direction <> Directions.None
End Function

类型转换器

虽然类型转换器通常将一种类型转换为另一种类型,但也为属性网格和其他设计时控件提供字符串到值的转换。 字符串到值的转换允许在这些设计时控件中表示复杂属性。

大多数内置数据类型(数字、枚举和其他类型)都有提供字符串到值转换和执行验证检查的默认类型转换器。 默认类型转换器位于 System.ComponentModel 命名空间中,以转换的类型命名。 转换器类型名称使用以下格式:{type name}Converter。 例如 StringConverterTimeSpanConverterInt32Converter

类型转换器在设计时与“属性”窗口广泛结合使用。 可以使用 TypeConverterAttribute 将类型转换器应用于属性或类型。

在属性上声明 TypeConverterAttribute 时,“属性”窗口使用转换器将属性显示为字符串值。 在类型上声明 TypeConverterAttribute 时,“属性”窗口对该类型的每个属性使用转换器。 类型转换器还有助于序列化设计器的代码隐藏文件中的属性值。

类型编辑器

当属性的类型为内置类型或已知类型时,“属性”窗口自动对属性使用类型编辑器。 例如,布尔值被编辑为 TrueFalse 值的组合框,DateTime 类型使用日历下拉列表。

重要

自 .NET Framework 以来,自定义类型编辑器已更改。 有关详细信息,请参阅自 .NET Framework(Windows 窗体 .NET)以来的设计器更改