在Visual Studio集成开发环境中,开发者可以通过自定义UITypeEditor类来实现在设计模式下对控件属性进行编辑。UITypeEditor类允许开发者创建下拉列表(DropDown)或模态表单(ModalForm)窗口,以实现设计时的属性编辑。本文将介绍如何使用UITypeEditor类,并提供一个基类PropertyEditorBase来简化自定义编辑器的开发过程。
要使用UITypeEditor,首先需要从该类继承并为控件属性添加Editor属性。以下是一个VB.NET的示例:
<Editor(GetType(MyPropertyEditor), GetType(System.Drawing.Design.UITypeEditor))> _
Public Property MyProperty As String
通过这种方式,可以为属性提供一个自定义的编辑器。
接下来,介绍PropertyEditorBase类。这是一个抽象类,继承自System.Drawing.Design.UITypeEditor。由于使用UITypeEditor类需要一些特殊代码,可以将这些代码放入一个基类(辅助类)中,以便后续更容易使用。
例如,当用户按下Esc键时,编辑过程应该被取消,并且之前的属性值应该返回到IDE的PropertyGrid中。或者,总是需要用一行代码获取IWindowsFormsEditorService服务:
Dim IEditorService As IWindowsFormsEditorService = DirectCast(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)
这些工作对于想要快速编写UITypeEditor的开发者来说可能不是很清楚。不会在这里详细说明,而是提供一个基类辅助类,以简化这个过程。
以下是PropertyEditorBase类的代码示例:
Public MustInherit Class PropertyEditorBase
Inherits System.Drawing.Design.UITypeEditor
Protected MustOverride Function GetEditControl(ByVal PropertyName As String, ByVal CurrentValue As Object) As Control
Protected MustOverride Function GetEditedValue(ByVal EditControl As Control, ByVal PropertyName As String, ByVal OldValue As Object) As Object
Protected IEditorService As IWindowsFormsEditorService
Private WithEvents m_EditControl As Control
Private m_EscapePressed As Boolean
Public Overrides Function GetEditStyle(ByVal context As ITypeDescriptorContext) As UITypeEditorEditStyle
Try
Dim c As Control = GetEditControl(context.PropertyDescriptor.Name, context.PropertyDescriptor.GetValue(context.Instance))
If TypeOf c Is Form Then
Return UITypeEditorEditStyle.Modal
Else
Return UITypeEditorEditStyle.DropDown
End If
Catch
Return MyBase.GetEditStyle(context)
End Try
End Function
Public Overrides Function EditValue(ByVal context As ITypeDescriptorContext, ByVal provider As IServiceProvider, ByVal value As Object) As Object
Try
If context IsNot Nothing AndAlso provider IsNot Nothing Then
Dim IEditorService As IWindowsFormsEditorService = DirectCast(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)
If IEditorService IsNot Nothing Then
Dim PropName As String = context.PropertyDescriptor.Name
m_EditControl = Me.GetEditControl(PropName, value)
If m_EditControl IsNot Nothing Then
m_EscapePressed = False
If TypeOf m_EditControl Is Form Then
IEditorService.ShowDialog(CType(m_EditControl, Form))
Else
IEditorService.DropDownControl(m_EditControl)
End If
If m_EscapePressed Then
Return value
Else
Return GetEditedValue(m_EditControl, PropName, value)
End If
End If
End If
End If
Catch ex As Exception
Return MyBase.EditValue(context, provider, value)
End Try
End Function
Public Function GetIWindowsFormsEditorService() As IWindowsFormsEditorService
Return IEditorService
End Function
Public Sub CloseDropDownWindow()
If IEditorService IsNot Nothing Then
IEditorService.CloseDropDown()
End If
End Sub
Private Sub m_EditControl_PreviewKeyDown(ByVal sender As Object, ByVal e As PreviewKeyDownEventArgs) Handles m_EditControl.PreviewKeyDown
If e.KeyCode = Keys.Escape Then
m_EscapePressed = True
End If
End Sub
End Class
PropertyEditorBase类有两个MustOverride(抽象)函数,需要由派生类定义。这两个函数是:
Function GetEditControl(ByVal PropertyName As String, ByVal CurrentValue As Object) As Control
Function GetEditedValue(ByVal EditControl As Control, ByVal PropertyName As String, ByVal OldValue As Object) As Object
第一个函数应该返回在属性编辑器窗口中使用的控件(例如一个简单的列表框),第二个函数应该返回正在编辑的属性的新值。派生类可以使用这些函数的参数信息来返回适当的值。例如,在ListBox示例中,基于属性的CurrentValue,下拉列表框的初始项被选中。
以下是一个使用PropertyEditorBase基类为'myProperty'属性定义编辑器的示例控件:
Public Class XTextBoxA
Inherits TextBox
Private m_myProperty As String = ""
<EditorAttribute(GetType(myListBoxPropertyEditor), GetType(System.Drawing.Design.UITypeEditor))> _
Public Property myProperty As String
Get
Return m_myProperty
End Get
Set(ByVal value As String)
m_myProperty = value
End Set
End Property
End Class
以下是myListBoxPropertyEditor类,它使用ListBox作为编辑控件:
Public Class myListBoxPropertyEditor
Inherits PropertyEditorBase
Private WithEvents myListBox As New ListBox
Protected Overrides Function GetEditControl(ByVal PropertyName As String, ByVal CurrentValue As Object) As Control
myListBox.BorderStyle = System.Windows.Forms.BorderStyle.None
myListBox.Items.Clear()
myListBox.Items.Add("AAA")
' ... Add other items...
myListBox.SelectedIndex = myListBox.FindString(CurrentValue)
myListBox.Height = myListBox.PreferredHeight
Return myListBox
End Function
Protected Overrides Function GetEditedValue(ByVal EditControl As Control, ByVal PropertyName As String, ByVal OldValue As Object) As Object
Return myListBox.Text
End Function
Private Sub myTreeView_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles myListBox.Click
Me.CloseDropDownWindow()
End Sub
End Class
应该在适当的事件中调用CloseDropDownWindow方法来关闭下拉编辑器窗口。对于ListBox,这是ListBox的Click事件,但对于TreeView,它可能是TreeView的DblClick事件。
可以使用这个基类来定义使用任何特殊控件的编辑器。例如,可以定义一个自定义UserControl,它显示一些图像(而不是文本风格的枚举列表),用于设置控制主控件图形视图的属性。