65.9K
CodeProject 正在变化。 阅读更多。
Home

在 VS.Net 设计时轻松创建属性编辑器 (UITypeEditor 助手)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (38投票s)

2007年1月9日

CPOL

2分钟阅读

viewsIcon

139701

downloadIcon

2828

这是一个帮助轻松创建 UITypeEditor 的基类。 它用于在 Visual Studio IDE 的设计模式下,在 DropDown 窗口或模态窗体中编辑控件属性。

引言

这是一个即用型代码,可帮助您在 Visual Studio IDE 的设计模式下,在 `DropDown` 或 `ModalForm` 窗口中,为控件属性的设计时编辑创建您自己的 `UITypeEditor`。 要使用它,请从中继承一个类,并将此属性添加到您的控件属性中。

<Editor(GetType(MyPropertyEditor), 
        GetType(System.Drawing.Design.UITypeEditor))>

以下图片显示了一些示例

 

ListBox DropDown Editor TreeView DropDown Editor
图 1) 使用 ListBox 编辑器 图 2) 使用 TreeView 编辑器

UserControl DropDown Editor

图 3) 使用 UserControl 编辑器
ModalForm Editor
图 4) 使用模态窗体编辑器

"PropertyEditorBase" 类

它是一个 abstract (MustInherit) 类,它本身继承自 `System.Drawing.Design.UITypeEditor`。 因为使用 `UITypeEditor` 类需要一些特殊代码,我们可以将它们放入一个基类(助手)中,并在以后更容易地使用它。

例如,当用户按下 Esc 键时,应取消编辑过程,并将先前的属性值返回到 IDE `PropertyGrid`。 或者,您始终需要使用类似于以下代码的一行代码来获取 `IWindowsFormsEditorService` 服务

IEditorService = 
   DirectCast(provider.GetService(GetType(IWindowsFormsEditorService)),
                                  IWindowsFormsEditorService )

对于想要快速编写 `UITypeEditor` 的开发人员来说,这些工作并不是很清楚。 我不会再多说,只会提供您可以用来简化此过程的基类助手。(如果您只想看看如何使用它,请参阅文章的这一部分。)

这是代码

Imports System.Drawing
Imports System.Drawing.Design
Imports System.Windows.Forms
Imports System.Windows.Forms.Design
Imports System.ComponentModel


''' <summary>

''' This is a UITypeEditor base class usefull for simple editing of control 
''' properties in a DropDown or a ModalForm window at design mode (in 
''' Visual Studio IDE). To use this, inherits a class from it and add this
''' attribute to your control property(ies): 
''' <Editor(GetType(MyPropertyEditor), 
'''         GetType(System.Drawing.Design.UITypeEditor))>  

''' </summary>

Public MustInherit Class PropertyEditorBase
    Inherits System.Drawing.Design.UITypeEditor

    ''' <summary>

    ''' The driven class should provide its edit Control to be shown in the 
    ''' DropDown or DialogForm window by means of this function. 
    ''' If specified control be a Form, it is shown in a Modal Form, otherwise 
    ''' in a DropDown window. This edit control should return its final value 
    ''' at GetEditedValue() method. 
    ''' </summary>

    Protected MustOverride Function GetEditControl(ByVal PropertyName As _
      String, ByVal CurrentValue As Object) As Control

    ''' <summary>The driven class should return the New Edited Value at this 

    ''' function.</summary>

    ''' <param name="EditControl">

    ''' The control shown in DropDown window and used for editing. 
    ''' This is the control you pass in GetEditControl() function.
    ''' </param>

    ''' <param name="OldValue">The original value of the property before 

    ''' editing</param>

    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

    ''' <summary>

    ''' Sets the edit style mode based on the type of EditControl: DropDown or
    ''' Modal(Dialog). 
    ''' Note that the driven class can also override this function and 
    ''' explicitly set its value.
    ''' </summary>

    Public Overrides Function GetEditStyle(ByVal context As _
                               ITypeDescriptorContext) As UITypeEditorEditStyle
        Try
            Dim c As Control
            c = GetEditControl(context.PropertyDescriptor.Name, _
                context.PropertyDescriptor.GetValue(context.Instance))
            If TypeOf c Is Form Then
                Return UITypeEditorEditStyle.Modal 'Using a Modal Form
            End If
        Catch
        End Try
        'Using a DropDown Window (This is the default style)
        Return UITypeEditorEditStyle.DropDown
    End Function

    'Displays the Custom UI (a DropDown Control or a Modal Form) for value 
    'selection.
    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

                'Uses the IWindowsFormsEditorService to display a drop-down
                'UI in the Properties window:
                IEditorService = DirectCast( _
                provider.GetService(GetType(IWindowsFormsEditorService)), _
                                    IWindowsFormsEditorService)

                If IEditorService IsNot Nothing Then

                    Dim PropName As String = context.PropertyDescriptor.Name

                    'get Edit Control from driven class
                    m_EditControl = Me.GetEditControl(PropName, value) 

                    If m_EditControl IsNot Nothing Then

                        m_EscapePressed = False    

                        'Show given EditControl
                        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 the Old Value 
                                                   '(because user press Escape)
                            Return value
                        Else 'get new (edited) value from driven class and 
                             'return it
                            Return GetEditedValue(m_EditControl, PropName, value)
                        End If

                    End If 'm_EditControl

                End If 'IEditorService

            End If 'context And provider

        Catch ex As Exception
            'we may show a MessageBox here...
        End Try
        Return MyBase.EditValue(context, provider, value)

    End Function

    ''' <summary>

    ''' Provides the interface for this UITypeEditor to display Windows Forms 
    ''' or to display a control in a DropDown area from the property grid 
    ''' control in design mode.
    ''' </summary>

    Public Function GetIWindowsFormsEditorService() As _
                                                   IWindowsFormsEditorService
        Return IEditorService
    End Function

    ''' <summary>Close DropDown window to finish editing</summary>

    Public Sub CloseDropDownWindow()
        If IEditorService IsNot Nothing Then IEditorService.CloseDropDown()
    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 Sub

End Class

如何使用

它有两个 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` 示例中,DropDown 列表框的初始项是根据属性的 `CurrentValue` 选择的。

ListBox 编辑器示例

这是一个示例控件,它使用此助手基类为其“myProperty”属性定义编辑器

Imports System.ComponentModel

Public Class XTextBoxA
    Inherits TextBox

    Private m_myProperty As String = ""

    'This property uses our custom UITypeEditor: myListBoxPropertyEditor
    <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 => using a ListBox as EditControl
' ////////////////////////////////////////////////////////////////////////////
'
Public Class myListBoxPropertyEditor
    Inherits PropertyEditorBase

    Private WithEvents myListBox As New ListBox 'this is the control to be used 
                                                'in design time DropDown editor

    Protected Overrides Function GetEditControl(ByVal PropertyName As String, _
      ByVal CurrentValue As Object) As Control

        myListBox.BorderStyle = System.Windows.Forms.BorderStyle.None

        'Creating ListBox items... 
        'Note that as this is executed in design mode, performance is not 
        'important and there is no need to cache listbox items if they can 
        'change each time.
        myListBox.Items.Clear()    'clear previous items if any
        myListBox.Items.Add("AAA")
        '... Add other items...

        'Select current item based on CurrentValue of the property:
        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 'return new value for property
    End Function


    Private Sub myTreeView_Click(ByVal sender As Object, ByVal e As _
                                     System.EventArgs) Handles myListBox.Click
        Me.CloseDropDownWindow() 'when user clicks on an item, the edit 
                                 'process is done.
    End Sub

End Class

您应该调用 `CloseDropDownWindow` 方法以在适当的事件中关闭 `DropDown` 编辑器窗口。 对于 `ListBox`,这是 `ListBox` 的 "`Click`" 事件,但对于 `TreeView`,可能是 TreeView 的 "`DblClick`" 事件。

注意

您可以使用此基类来定义使用任何特殊控件的编辑器。 例如,您可以定义一个自定义 `UserControl`,它显示一些图像(而不是文本样式的 `Enum` 列表)来设置控制主控件图形视图的属性。

下载源代码以查看图 1 至图 4 中显示的所有四个示例

另请参阅

SmartTagDesigner 文章: 帮助开发人员通过智能标记设计器面板构建组件和控件的自定义设计时扩展。

© . All rights reserved.