充分利用 .NET 框架的 PropertyGrid 控件(微软)之七
使用此版本的选项窗口后,您会注意到以下几点:
显示窗口时,将首先突出显示 SaveOnClose 属性。
选中 MaxRepeatRate 属性时,说明帮助窗格中将显示“以毫秒表示的文本重复率”。
SaveOnClose 属性显示在“文档设置”类别下。其他属性分别显示在“全局设置”和“版本”类别下。
SettingsChanged 属性将不再显示。
AppVersion 属性为只读。只读属性以灰显文本显示。
如果 SaveOnClose 属性包含的值不是 true,该值将以粗体显示。PropertyGrid 使用粗体文本表示包含非默认值的属性。
显示复杂属性
到现在为止,选项窗口显示的都是简单的类型,如整数、布尔值和字符串。那么,如何显示更复杂的类型呢?如果应用程序需要跟踪窗口大小、文档字体或工具栏颜色等信息,该如何处理呢?.NET 框架提供的某些数据类型具有特殊的显示功能,能使这些类型在 PropertyGrid 中更具可用性。
对所提供类型的支持
首先,请更新 AppSettings 类,为窗口大小(Size 类型)、窗口字体(Font 类型)和工具栏颜色(Color 类型)添加新属性。
' Visual Basic
<DefaultPropertyAttribute("SaveOnClose")> _
Public Class AppSettings
Private _saveOnClose As Boolean = True
Private _greetingText As String = "欢迎使用应用程序!"
Private _maxRepeatRate As Integer = 10
Private _itemsInMRU As Integer = 4
Private _settingsChanged As Boolean = False
Private _appVersion As String = "1.0"
Private _windowSize As Size = New Size(100, 100)
Private _windowFont As Font = New Font("宋体", 9, FontStyle.Regular)
Private _toolbarColor As Color = SystemColors.Control
<CategoryAttribute("文档设置"), _
DefaultValueAttribute(True)> _
Public Property SaveOnClose() As Boolean
Get
Return _saveOnClose
End Get
Set(ByVal Value As Boolean)
SaveOnClose = Value
End Set
End Property
<CategoryAttribute("文档设置")> _
Public Property WindowSize() As Size
Get
Return _windowSize
End Get
Set(ByVal Value As Size)
_windowSize = Value
End Set
End Property
<CategoryAttribute("文档设置")> _
Public Property WindowFont() As Font
Get
Return _windowFont
End Get
Set(ByVal Value As Font)
_windowFont = Value
End Set
End Property
<CategoryAttribute("全局设置")> _
Public Property ToolbarColor() As Color
Get
Return _toolbarColor
End Get
Set(ByVal Value As Color)
_toolbarColor = Value
End Set
End Property
<CategoryAttribute("全局设置"), _
ReadOnlyAttribute(True), _
DefaultValueAttribute("欢迎使用应用程序!")> _
Public Property GreetingText() As String
Get
Return _greetingText
End Get
Set(ByVal Value As String)
_greetingText = Value
End Set
End Property
<CategoryAttribute("全局设置"), _
DefaultValueAttribute(4)> _
Public Property ItemsInMRUList() As Integer
Get
Return _itemsInMRU
End Get
Set(ByVal Value As Integer)
_itemsInMRU = Value
End Set
End Property
<DescriptionAttribute("以毫秒表示的文本重复率。"), _
CategoryAttribute("全局设置"), _
DefaultValueAttribute(10)> _
Public Property MaxRepeatRate() As Integer
Get
Return _maxRepeatRate
End Get
Set(ByVal Value As Integer)
_maxRepeatRate = Value
End Set
End Property
<BrowsableAttribute(False),
DefaultValueAttribute(False)> _
Public Property SettingsChanged() As Boolean
Get
Return _settingsChanged
End Get
Set(ByVal Value As Boolean)
_settingsChanged = Value
End Set
End Property
<CategoryAttribute("版本"), _
DefaultValueAttribute("1.0"), _
ReadOnlyAttribute(True)> _
Public Property AppVersion() As String
Get
Return _appVersion
End Get
Set(ByVal Value As String)
_appVersion = Value
End Set
End Property
End Class
请注意,WindowFont 属性带有一个省略号 (...) 按钮,按下该按钮将显示字体选择对话框。此外,还可以展开该属性以显示更多的 Font 属性。某些 Font 属性提供有关字体的值和详细信息的下拉列表。您可以展开 WindowSize 属性以显示 Size 类型的更多属性。最后,请注意,ToolbarColor 属性包含一个选定颜色的样本,以及一个用于选择不同颜色的自定义下拉列表。对于这些以及其他数据类型,.NET 框架提供了其他的类,可以使在 PropertyGrid 中的编辑更加容易。
对自定义类型的支持
现在,您需要在 AppSettings 类中添加另外两个属性,即 DefaultFileName 和 SpellCheckOptions。 DefaultFileName 属性用于获取或设置字符串;SpellCheckOptions 属性用于获取或设置 SpellingOptions 类的实例。
SpellingOptions 类是一个新类,用于管理应用程序的拼写检查属性。对于何时创建单独的类以管理对象的属性,并没有严格的规定,而取决于您的整个类设计。将 SpellingOptions 类定义添加到应用程序项目中 - 可以添加到新文件中,也可以添加到窗体源代码的下方。
' Visual Basic
<DescriptionAttribute("展开以查看应用程序的拼写选项。")> _
Public Class SpellingOptions
Private _spellCheckWhileTyping As Boolean = True
Private _spellCheckCAPS As Boolean = False
Private _suggestCorrections As Boolean = True
<DefaultValueAttribute(True)> _
Public Property SpellCheckWhileTyping() As Boolean
Get
Return _spellCheckWhileTyping
End Get
Set(ByVal Value As Boolean)
_spellCheckWhileTyping = Value
End Set
End Property
<DefaultValueAttribute(False)> _
Public Property SpellCheckCAPS() As Boolean
Get
Return _spellCheckCAPS
End Get
Set(ByVal Value As Boolean)
_spellCheckCAPS = Value
End Set
End Property
<DefaultValueAttribute(True)> _
Public Property SuggestCorrections() As Boolean
Get
Return _suggestCorrections
End Get
Set(ByVal Value As Boolean)
_suggestCorrections = Value
End Set
End Property
End Class
请注意 SpellcheckOptions 属性的外观。与 .NET 框架类型不同,它不展开或显示自定义的字符串表示。如果要在自己的复杂类型中提供与 .NET 框架类型相同的编辑体验,该如何处理呢?.NET 框架类型使用 TypeConverter 和 UITypeEditor 类提供大部分 PropertyGrid 编辑支持,您也可以使用这些类。
添加可展开属性支持
要使 PropertyGrid 能够展开 SpellingOptions 属性,您需要创建 TypeConverter。TypeConverter 提供了从一种类型转换为另一种类型的方法。PropertyGrid 使用 TypeConverter 将对象类型转换为 String,并使用该 String 在网格中显示对象值。在编辑过程中,TypeConverter 会将 String 转换回对象类型。.NET 框架提供的 ExpandableObjectConverter 类可以简化这一过程。
提供可展开对象支持
创建一个从 ExpandableObjectConverter 继承而来的类。
' Visual Basic
Public Class SpellingOptionsConverter
Inherits ExpandableObjectConverter
End Class
如果 destinationType 参数与使用此类型转换器的类(示例中的 SpellingOptions 类)的类型相同,则覆盖 CanConvertTo 方法并返回 true;否则返回基类 CanConvertTo 方法的值。
' Visual Basic
Public Overloads Overrides Function CanConvertTo( _
ByVal context As ITypeDescriptorContext, _
ByVal destinationType As Type) As Boolean
If (destinationType Is GetType(SpellingOptions)) Then
Return True
End If
Return MyBase.CanConvertTo(context, destinationType)
End Function
覆盖 ConvertTo 方法,并确保 destinationType 参数是一个 String,并且值的类型与使用此类型转换器的类(示例中的 SpellingOptions 类)相同。如果其中任一情况为 false,都将返回基类 ConvertTo 方法的值;否则,返回值对象的字符串表示。字符串表示需要使用唯一分隔符将类的每个属性隔开。由于整个字符串都将显示在 PropertyGrid 中,因此需要选择一个不会影响可读性的分隔符,逗号的效果通常比较好。
' Visual Basic
Public Overloads Overrides Function ConvertTo( _
ByVal context As ITypeDescriptorContext, _
ByVal culture As CultureInfo, _
ByVal value As Object, _
ByVal destinationType As System.Type) _
As Object
If (destinationType Is GetType(System.String) _
AndAlso TypeOf value Is SpellingOptions) Then
Dim so As SpellingOptions = CType(value, SpellingOptions)
Return "在键入时检查: " & so.SpellCheckWhileTyping & _
",检查大小写: " & so.SpellCheckCAPS & _
",建议更正: " & so.SuggestCorrections
End If
Return MyBase.ConvertTo(context, culture, value, destinationType)
End Function
(可选)通过指定类型转换器可以从字符串进行转换,您可以启用网格中对象字符串表示的编辑。要执行此操作,首先需要覆盖 CanConvertFrom 方法并返回 true(如果源 Type 参数为 String 类型);否则,返回基类 CanConvertFrom 方法的值。
' Visual Basic
Public Overloads Overrides Function CanConvertFrom( _
ByVal context As ITypeDescriptorContext, _
ByVal sourceType As System.Type) As Boolean
If (sourceType Is GetType(String)) Then
Return True
End If
Return MyBase.CanConvertFrom(context, sourceType)
End Function
要启用对象基类的编辑,同样需要覆盖 ConvertFrom 方法并确保值参数是一个 String。如果不是 String,将返回基类 ConvertFrom 方法的值;否则,返回基于值参数的类(示例中的 SpellingOptions 类)的新实例。您需要根据值参数解析类的每个属性的值。了解在 ConvertTo 方法中创建的分隔字符串的格式将有助于您的解析。
' Visual Basic
Public Overloads Overrides Function ConvertFrom( _
ByVal context As ITypeDescriptorContext, _
ByVal culture As CultureInfo, _
ByVal value As Object) As Object
If (TypeOf value Is String) Then
Try
Dim s As String = CStr(value)
Dim colon As Integer = s.IndexOf(":")
Dim comma As Integer = s.IndexOf(",")
If (colon <> -1 AndAlso comma <> -1) Then
Dim checkWhileTyping As String = s.Substring(colon + 1, _
(comma - colon - 1))
colon = s.IndexOf(":", comma + 1)
comma = s.IndexOf(",", comma + 1)
Dim checkCaps As String = s.Substring(colon + 1, _
(comma - colon - 1))
colon = s.IndexOf(":", comma + 1)
Dim suggCorr As String = s.Substring(colon + 1)
Dim so As SpellingOptions = New SpellingOptions()
so.SpellCheckWhileTyping = Boolean.Parse(checkWhileTyping)
so.SpellCheckCAPS = Boolean.Parse(checkCaps)
so.SuggestCorrections = Boolean.Parse(suggCorr)
Return so
End If
Catch
Throw New ArgumentException( _
"无法将“" & CStr(value) & _
"”转换为 SpellingOptions 类型")
End Try
End If
Return MyBase.ConvertFrom(context, culture, value)
End Function
现在已经有了一个类型转换器类,下面您需要确定使用该类的目标类。您可以通过将 TypeConverterAttribute 应用到目标类(示例中的 SpellingOptions 类)来执行此操作。
' Visual Basic
' 应用于 SpellingOptions 类的 TypeConverter 特性。
<TypeConverter(GetType(SpellingOptionsConverter)), _
DescriptionAttribute("展开以查看应用程序的拼写选项。")> _
Public Class SpellingOptions
...
End Class
// 应用于 SpellingOptions 类的 TypeConverter 特性。
[TypeConverterAttribute(typeof(SpellingOptionsConverter)),
DescriptionAttribute("展开以查看应用程序的拼写选项。")]
public class SpellingOptions{ ... }
再次编译并运行选项窗口应用程序。下面的屏幕快照显示了选项窗口目前的外观。
图 6:在 PropertyGrid 中显示的带有类型转换器的自定义数据类型
注意: 如果只需要可展开对象支持,而不需要自定义字符串表示,则只需将 TypeConverterAttribute 应用到类中。将 ExpandableObjectConverter 指定为类型转换器类型。