发现了一个自定义PropertyGrid的简洁方法。还有许多不明白的地方,希望得到指点!
网上见对多种自定义PropertyGrid的方法,但相当复杂,我看不太明白。接下来发现了一个比较简洁的方法,代码如下。但还有许多不明白的地方,例如如何打开文件、路径、Combobox甚至自定义编辑器等等,希望得到指点!Imports System
Imports
Public Class Form2
Private PGClass As New CustomClass()
Private Enum UserEnum
男
女
End Enum
Private Sub Form2_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim PGDate As DateTime = DateTime.Now
Dim PGArrayList As New ArrayList()
PGArrayList.Add(\"集合元素-1\")
PGArrayList.Add(\"集合元素-2\")
Dim PGCollectionText1 As String() = New String() {\"集合元素-1\", \"集合元素-2\"}
Dim PGCollectionText2 As String() = New [String](2) {}
PGCollectionText2(0) = \"集合元素-1\"
PGCollectionText2(1) = \"集合元素-2\"
Dim IntegerList As Integer() = New Integer() {1, 2}
PGClass.AddProperty(\"整数输入\", GetType(Integer), \"备注信息\", 1, \"分类-数值\", False)
PGClass.AddProperty(\"集合编辑器-整数\", IntegerList.GetType, \"备注信息\", IntegerList, \"分类-数值\", False)
PGClass.AddProperty(\"文本输入\", \"\".GetType, \"备注信息\", \"默认文本\", \"分类-字符\", False)
PGClass.AddProperty(\"集合编辑器-文本-定义方式1\", PGCollectionText1.GetType, \"备注信息\", PGCollectionText1, \"分类-字符\", False)
PGClass.AddProperty(\"集合编辑器-文本-定义方式2\", PGCollectionText2.GetType, \"备注信息\", PGCollectionText2, \"分类-字符\", False)
PGClass.AddProperty(\"集合编辑器-文本-对象\", PGArrayList.GetType(), \"备注信息\", PGArrayList, \"分类-字符\", False)
PGClass.AddProperty(\"Enum列表\", GetType(UserEnum), \"备注信息\", UserEnum.男, \"分类-字符\", False)
PGClass.AddProperty(\"字体\", GetType(Font), \"备注信息\", New Font(\"宋体\", 10.0F), \"分类-系统\", False)
PGClass.AddProperty(\"颜色-自定义\", GetType(Color), \"备注信息\", Color.FromArgb(255, 0, 0), \"分类-系统\", False)
PGClass.AddProperty(\"颜色-系统\", GetType(Color), \"备注信息\", SystemColors.Control, \"分类-系统\", False)
PGClass.AddProperty(\"大小\", GetType(Size), \"备注信息\", New Size(100, 100), \"分类-系统\", False)
PGClass.AddProperty(\"位置\", GetType(Point), \"备注信息\", New Point(100, 100), \"分类-系统\", False)
PGClass.AddProperty(\"语言\", GetType(System.Globalization.CultureInfo), \"备注信息\", New System.Globalization.CultureInfo(\"zh-CN\"), \"分类-系统\", False)
PGClass.AddProperty(\"日期时间\", GetType(Date), \"备注信息\", DateTime.Now, \"分类-系统\", False)
PGClass.AddProperty(\"日期\", GetType(DateTime), \"备注信息\", New DateTime(Now.Year, Now.Month, Now.Day), \"分类-系统\", False)
PGClass.AddProperty(\"时间\", GetType(TimeSpan), \"备注信息\", New TimeSpan, \"分类-系统\", False)
PGClass.AddProperty(\"逻辑\", GetType(Boolean), \"备注信息\", False, \"分类-系统\", False)
Dim UserDialog As New OpenFileDialog \'这是错误的。本来想打开文件对话框,但结果是列出了文件对话框的所有属性!
PGClass.AddProperty(\"对话框\", UserDialog.GetType, \"备注信息\", UserDialog, \"分类-对话框\", False)
PropertyGrid1.SelectedObject = PGClass
End Sub
<TypeConverter(GetType(ExpandableObjectConverter))> Public Class CustomClass
Inherits Component
Implements ICustomTypeDescriptor
Private categoryList As ArrayList
Private dataTypeList As ArrayList
Public Sub New()
myTable = New DataTable(\"Properties\")
categoryList = New ArrayList()
dataTypeList = New ArrayList()
End Sub
Public Sub AddProperty(ByVal propName As String, ByVal propType As System.Type, ByVal propDesc As String, ByVal propValue As Object, ByVal categoryItem As String, ByVal isArray As Boolean)
Dim myDC As New DataColumn(propName, propType)
myDC.Caption = propDesc
myTable.Columns.Add(myDC)
If myTable.Rows.Count = 0 Then
Dim myDR As DataRow = myTable.NewRow()
myTable.Rows.Add(myDR)
End If
Me(propName) = propValue
categoryList.Add(categoryItem)
dataTypeList.Add(isArray)
End Sub
Default Public Property Item(ByVal name As String) As Object
Get
Return myTable.Rows(0)(name)
End Get
Set(ByVal value As Object)
myTable.Rows(0)(name) = value
End Set
End Property
Private myTable As DataTable
Private privateProp As PropertyDescriptorCollection
Public Function GetClassName() As String Implements ICustomTypeDescriptor.GetClassName
Return (TypeDescriptor.GetClassName(Me, True))
End Function
Public Function GetAttributes() As AttributeCollection Implements ICustomTypeDescriptor.GetAttributes
Return (TypeDescriptor.GetAttributes(Me, True))
End Function
Public Function GetComponentName() As String Implements ICustomTypeDescriptor.GetComponentName
Return (TypeDescriptor.GetComponentName(Me, True))
End Function
Public Function GetConverter() As TypeConverter Implements ICustomTypeDescriptor.GetConverter
Return (TypeDescriptor.GetConverter(Me, True))
End Function
Public Function GetDefaultEvent() As EventDescriptor Implements ICustomTypeDescriptor.GetDefaultEvent
Return (TypeDescriptor.GetDefaultEvent(Me, True))
End Function
Public Function GetDefaultProperty() As PropertyDescriptor Implements ICustomTypeDescriptor.GetDefaultProperty
Dim myProps As PropertyDescriptorCollection = GetAllProperties()
If myProps.Count > 0 Then
Return (myProps(0))
Else
Return (Nothing)
End If
End Function
Public Function GetEditor(ByVal editorBaseType As Type) As Object Implements ICustomTypeDescriptor.GetEditor
Return (TypeDescriptor.GetEditor(Me, editorBaseType, True))
End Function
Public Function GetEvents(ByVal attributes As Attribute()) As EventDescriptorCollection Implements ICustomTypeDescriptor.GetEvents
Return (TypeDescriptor.GetEvents(Me, attributes, True))
End Function
Public Function GetEvents() As EventDescriptorCollection Implements ICustomTypeDescriptor.GetEvents
Return (TypeDescriptor.GetEvents(Me, True))
End Function
Public Function GetProperties(ByVal attributes As Attribute()) As PropertyDescriptorCollection Implements ICustomTypeDescriptor.GetProperties
Return (GetAllProperties())
End Function
Public Function GetProperties() As PropertyDescriptorCollection Implements ICustomTypeDescriptor.GetProperties
Return (GetAllProperties())
End Function
Public Function GetPropertyOwner(ByVal pd As PropertyDescriptor) As Object Implements ICustomTypeDescriptor.GetPropertyOwner
Return (Me)
End Function
Private Function GetAllProperties() As PropertyDescriptorCollection
If privateProp Is Nothing Then
privateProp = New PropertyDescriptorCollection(New PropertyDescriptor() {})
Dim i As Integer = 0
For Each myDC As DataColumn In myTable.Columns
Dim myANC As New AddNewColumn(myDC, categoryList(i).ToString(), CBool(dataTypeList(i)))
privateProp.Add(myANC)
Dim myPDC As PropertyDescriptorCollection = myANC.GetChildProperties()
i += 1
Next
End If
Return privateProp
End Function
Public Class AddNewColumn
Inherits PropertyDescriptor
Private myDC As DataColumn
Private insertCategory As String
Private myType As Type
Private isExpandable As Boolean
Public Sub New(ByVal thisDC As DataColumn, ByVal insCat As String, ByVal expandable As Boolean)
MyBase.New(thisDC.ColumnName, New Attribute() {})
myDC = thisDC
myType = thisDC.[GetType]()
insertCategory = insCat
isExpandable = expandable
End Sub
Public Overloads Overrides ReadOnly Property ComponentType() As System.Type
Get
Return Nothing
End Get
End Property
Public Overloads Overrides ReadOnly Property Category() As String
Get
Return insertCategory
End Get
End Property
Public Overloads Overrides ReadOnly Property IsReadOnly() As Boolean
Get
Return myDC.[ReadOnly]
End Get
End Property
Public Overloads Overrides ReadOnly Property PropertyType() As System.Type
Get
If isExpandable Then
Return myType
Else
Return myDC.DataType
End If
End Get
End Property
Public Overloads Overrides Function CanResetValue(ByVal component As Object) As Boolean
Return True
End Function
Public Overloads Overrides Function GetValue(ByVal component As Object) As Object
Dim myCC As CustomClass = TryCast(component, CustomClass)
If myCC IsNot Nothing Then
Return myCC(myDC.ColumnName)
Else
Throw New ArgumentException(\"Component is not derived from DynamicProperties\")
End If
End Function
Public Overloads Overrides Sub SetValue(ByVal component As Object, ByVal value As Object)
Dim myCC As CustomClass = TryCast(component, CustomClass)
If myCC IsNot Nothing Then
myCC(myDC.ColumnName) = value
Else
Throw New ArgumentException(\"Component is not derived from DynamicProperties\")
End If
End Sub
Public Overloads Overrides Sub ResetValue(ByVal component As Object)
Dim myCC As CustomClass = TryCast(component, CustomClass)
If myCC IsNot Nothing Then
myCC(myDC.ColumnName) = Nothing
Else
Throw New ArgumentException(\"Component is not derived from DynamicProperties\")
End If
End Sub
Public Overloads Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean
Return False
End Function
Public Overloads Overrides ReadOnly Property Description() As String
Get
Return myDC.Caption
End Get
End Property
End Class
End Class
End Class
此外,可以通过PGClass.Item(\"属性名称\").ToString返回指定属性的值。