如果你对 PropertyGrid 完全不了解,请先阅读 woyouxian 撰写的"用 PropertyGrid 实现 Visual Studio 2005 样式的属性窗口 (Properties Window)" 一文,要是还没有来得及读的话……那就赶紧去读吧!
由于文章篇幅的关系,本文的代码中省去了所有的注释。你具体写代码的时候,一定要把注释补上,如果没有写又看不懂自己代码的话,也没啥大不了,我相信你已经把站长网 站长学院加到收藏夹里面了。
本文主要介绍的是,如何对PropertyGrid中某个属性定义下拉框的功能。如下图所示。

打开 Visual Studio。在文件 (File) 菜单上,单击新建项目 (New Project)。 在新建项目 (New Project) 对话框的模板 (Templates) 窗格中,单击 Windows 应用程序 (Windows Application)。在名称 (Name) 框中键入 PropGrid,再单击确定 (OK)。
在 Solution Explorer 里选中 Form1.vb,改名为PropGridEx.vb。选中该 Form,在 Properties 窗口将该 Form 的 Text 属性设为 PropGridEx - www.admin5.com/html。
在 Toolbox 的 All Windows Forms 里选中 PropertyGrid 控件,将其拖到 Form 上。在 Properties 窗口将 PropertyGrid 的 Name 属性改为 PGrid。

点击Solution Explorer上的 View Code 按钮进入代码编辑器,你会看到如下代码。
Public Class PropGridEx
End Class
在上述代码的最后追加下面的代码,创建 Class Demo。
Public Class Demo
#Region "Private Variables"
Private theCountry As String
Private theLanguage As String
#End Region
#Region "Public Properties"
Public Property Country() As String
Get
Return theCountry
End Get
Set(ByVal value As String)
theCountry = value
End Set
End Property
Public Property Language() As String
Get
Return theLanguage
End Get
Set(ByVal value As String)
theLanguage = value
End Set
End Property
#End Region
End Class
注意,以上代码不能写在文件的开始。因为这是一个 Windows Form 的 vb 文件,第一个类必须是表示窗体的类。
然后在窗体事件 Load 中将 Demo 的一个对象和 PGrid 关联起来。整个窗体部分的代码如下。
Public Class PropGridEx
Private theDemo As Demo = New Demo
Private Sub PropGridEx_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
PGrid.SelectedObject = theDemo
End Sub
End Class
运行程序,得到下面的画面。

先把代码显摆出来再慢慢解释吧。
第一步,在文件的开始增加对System.ComponentModel的Imports;
Imports System.ComponentModel
第二步,在文件的结尾增加一个类StrChoice;
Public Class StrChoice
Inherits StringConverter
Dim theValues As TypeConverter.StandardValuesCollection
Public Overrides Function GetStandardValuesSupported( _
ByVal context As ITypeDescriptorContext) As Boolean
Return True
End Function
Public Overrides Function GetStandardValuesExclusive( _
ByVal context As ITypeDescriptorContext) As Boolean
Return True
End Function
Public Overrides Function GetStandardValues( _
ByVal context As ITypeDescriptorContext) _
As TypeConverter.StandardValuesCollection
Return Values
End Function
Private ReadOnly Property Values() As
TypeConverter.StandardValuesCollection
Get
If theValues Is Nothing Then
theValues = New TypeConverter.StandardValuesCollection( _
New String() {"China", "USA", "Germany"})End If
Return theValues
End Get
End Property
End Class
第三步,在前面建立出来的 Class Demo 中修改 Country 的定义为下面的代码。
......
<TypeConverter(GetType(StrChoice))> _
Public Property Country() As String
......
运行代码,就可以看到下拉框了。

接下来解释一下这些代码。
除了这些解释之外,还要补充两件事。
第一,在代码编辑器里面,一输入 Overrides,后面就会自动弹出一个可以 Overrides 的成员列表。TypeConverter 或者 StringConverter 可以 Overrides 的成员有很多,和上面提到的三个成员名字相似的还有两个:GetProperties 和 GetPropertiesSupported。这些成员的名字都是老长的英文,参数也差不多,一不小心就会选错了。我第一次写这个代码的时候就选错了,任凭无数脏话在我胸中翻腾,下拉框死也不出来。后来看了个BT下载的片儿后头脑冷静的细看代码才找到问题,你写的时候就别受罪了。
第二,Values那个函数中有一句这么写的,
theValues = New TypeConverter.StandardValuesCollection( _
New String() {"China", "USA", "Germany"})这里多少有些卖弄技巧的成分。如果老老实实的写代码应该是下面这个样子。
Dim strs(2) As String
strs(0) = "China"
strs(1) = "USA"
strs(2) = "Germany"
theValues = New TypeConverter.StandardValuesCollection(strs)
如果有好几个属性值都需要下拉框,而且下拉框的内容都不相同,那是不是要写很多个类呢?并非如此,可以用下面的方法把下拉列表的值写到属性的定义中去。
第一步,在文件的最后再追加一个类 StrListAttribute;
Public Class StrListAttribute
Inherits Attribute
Private theList As String()
Public Sub New(ByVal list As String())
theList = list
End Sub
Public ReadOnly Property List() As String()
Get
Return theList
End Get
End Property
End Class
第二步,在类 StrChoice 中删除 Values 属性,并修改 GetStandardValues 的代码;
Public Class StrChoice
Inherits StringConverter
Dim theValues As TypeConverter.StandardValuesCollection
Public Overrides Function GetStandardValuesSupported( _
ByVal context As ITypeDescriptorContext) As Boolean
Return True
End Function
Public Overrides Function GetStandardValuesExclusive( _
ByVal context As ITypeDescriptorContext) As Boolean
Return True
End Function
Public Overrides Function GetStandardValues( _
ByVal context As ITypeDescriptorContext) _
As TypeConverter.StandardValuesCollection
If theValues Is Nothing Then
Dim slist As StrListAttribute = _
context.PropertyDescriptor.Attributes(GetType(StrListAttribute))
theValues = New TypeConverter.StandardValuesCollection(slist.List)
End If
Return theValues
End Function
End Class
第三步,修改Demo中的属性定义,把下拉列表值定义进去。
......
<TypeConverter(GetType(StrChoice)), _
StrList(New String() {"China", "USA", "Germany"})> _Public Property Country() As String
......
<TypeConverter(GetType(StrChoice)), _
StrList(New String() {"Chinese", "English", "German"})> _Public Property Language() As String
......
运行代码后可以看到不同的下拉框出现了不同的下拉列表。

下面是对代码的一些说明。
如果有些下拉值的集合会被很多类的属性反复用到的话,每次都写一堆值的集合一来比较辛苦,二来一旦需要增减个把下拉选项的话,就需要修改N多处程序。要解决这个需求,可以增强 StrListAttribute 这个类如下。
Imports System.Collections.Generic
......
Public Class StrListAttribute
Inherits Attribute
Private Shared theListColl As Dictionary(Of String, String())
Private theList As String()
Public Sub New(ByVal list As String())
theList = list
End Sub
Public Sub New(ByVal name As String)
If ListColl.ContainsKey(name) Then
theList = ListColl.Item(name)
Else
theList = New String() {name}End If
End Sub
Public ReadOnly Property List() As String()
Get
Return theList
End Get
End Property
Private Shared ReadOnly Property ListColl() As Dictionary(Of String, String())
Get
If theListColl Is Nothing Then
theListColl = New Dictionary(Of String, String())
theListColl.Add("Country", _ New String() {"China", "USA", "Germany"}) theListColl.Add("Language", _ New String() {"Chinese", "English", "German"})End If
Return theListColl
End Get
End Property
End Class
这样的话,就可以用下面的代码来定义 Demo 中的属性了。
......
<TypeConverter(GetType(StrChoice)), StrList("Country")> _Public Property Country() As String
......
<TypeConverter(GetType(StrChoice)), StrList("Language")> _Public Property Language() As String
......
说明如下,
如果要把下拉列表的值定义在Xml文件或者数据库中,那只要在 StrListAttribute 增加些成员就 OK了,这已经和 PropertyGrid 的扩展是相对独立的问题了,是如何把 Xml 或数据库和 Dictionary 对应的问题了。希望你自己可以搞定,如果实在搞不定的话,请阅读 www.admin5.com/html 里面有关 Xml、数据库和 Collection 的相关文章。
作者:miyiyi[at]gmail[dot]com
时间:2006-12-27
站长网 站长学院网页教程与代码
免费收录站长网站
站长网信息中心
站长网 idc频道