自定义控件的设计时属性

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

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

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

定义属性

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

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

注释

无法隐式转换为字符串和从字符串转换的复杂属性需要类型转换器。

序列化属性

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

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

默认值

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

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

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

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

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

重要

应用属性 DefaultValueAttribute ,或同时提供这两者 Reset<PropertyName> 以及 ShouldSerialize<PropertyName> 方法。 不要混合定义默认值的两种方式。

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

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

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

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

默认值属性

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

重要

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

以下代码声明两个属性:默认值为 North 10 的枚举和一个默认值为 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> 方法不仅提供了引导属性重置行为的机会,还用于判断值是否变更,并应序列化到设计器的后台代码文件中。 两种方法需要协同工作,不能单独定义其中一个而不定义另一个。

重要

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

定义 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 以来的设计器更改