通过实现一个用户界面 (UI) 类型编辑器,您可以为复杂的属性类型提供自定义设计时体验。
本演练说明如何为一个自定义类型创作您自己的 UI 类型编辑器并使用 PropertyGrid 来显示其编辑界面。
本演练中阐释的任务包括:
- 定义自定义类型。
- 为您的 UI 类型编辑器定义视图控件。
- 定义一个从 UITypeEditor 派生的类。
- 重写 GetEditStyle 方法以通知 PropertyGrid 编辑器将使用的编辑器样式的类型。
- 重写 EditValue 方法以处理用户界面、用户输入处理和赋值。
若要将本演练中的代码作为单个清单复制,请参见如何:创建利用设计时功能的 Windows 窗体控件。
先决条件
- 拥有在安装有 .NET Framework 的计算机上创建和运行 Windows 窗体应用程序项目的足够权限。
定义自定义类型
您的自定义 UI 类型编辑器将显示自定义类型。此类型可能比较复杂,也可能比较简单。本演练将定义一个具有自定义设计时编辑行为的简单类型。此类型名为 MarqueeLightShape,它是一个具有两个值(Square 和 Circle)的 enum。
定义自定义枚举类型
- 在您的 Windows 窗体控件的定义体中,定义 MarqueeLightShape 类型。
Visual Basic
' This defines the possible values for the MarqueeBorder
' control's LightShape property.
Public Enum MarqueeLightShape
Square
Circle
End Enum
定义视图控件
您的自定义 UI 类型编辑器使用一个 Windows 窗体控件来显示编辑界面。此控件名为 LightShapeSelectionControl,它是从 UserControl 派生的。它的构造函数采用当前属性值和一个对 IWindowsFormsEditorService 的引用。当用户单击一个选择时,视图控件对 IWindowsFormsEditorService 使用 CloseDropDown 方法来关闭下拉窗口。
定义视图控件
- 在您的 Windows 窗体控件的定义体中,定义 LightShapeSelectionControl 控件。
Visual Basic
' This control provides the custom UI for the LightShape property
' of the MarqueeBorder. It is used by the LightShapeEditor.
Public Class LightShapeSelectionControl
Inherits System.Windows.Forms.UserControl
Private lightShapeValue As MarqueeLightShape = MarqueeLightShape.Square
Private editorService As IWindowsFormsEditorService
Private squarePanel As System.Windows.Forms.Panel
Private circlePanel As System.Windows.Forms.Panel
' Required designer variable.
Private components As System.ComponentModel.Container = Nothing
' This constructor takes a MarqueeLightShape value from the
' design-time environment, which will be used to display
' the initial state.
Public Sub New( _
ByVal lightShape As MarqueeLightShape, _
ByVal editorService As IWindowsFormsEditorService)
' This call is required by the Windows.Forms Form Designer.
InitializeComponent()
' Cache the light shape value provided by the
' design-time environment.
Me.lightShapeValue = lightShape
' Cache the reference to the editor service.
Me.editorService = editorService
' Handle the Click event for the two panels.
AddHandler Me.squarePanel.Click, AddressOf squarePanel_Click
AddHandler Me.circlePanel.Click, AddressOf circlePanel_Click
End Sub
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
' Be sure to unhook event handlers
' to prevent "lapsed listener" leaks.
RemoveHandler Me.squarePanel.Click, AddressOf squarePanel_Click
RemoveHandler Me.circlePanel.Click, AddressOf circlePanel_Click
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
' LightShape is the property for which this control provides
' a custom user interface in the Properties window.
Public Property LightShape() As MarqueeLightShape
Get
Return Me.lightShapeValue
End Get
Set(ByVal Value As MarqueeLightShape)
If Me.lightShapeValue <> Value Then
Me.lightShapeValue = Value
End If
End Set
End Property
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e)
Dim gCircle As Graphics = Me.circlePanel.CreateGraphics()
Try
Dim gSquare As Graphics = Me.squarePanel.CreateGraphics()
Try
' Draw a filled square in the client area of
' the squarePanel control.
gSquare.FillRectangle( _
Brushes.Red, _
0, _
0, _
Me.squarePanel.Width, _
Me.squarePanel.Height)
' If the Square option has been selected, draw a
' border inside the squarePanel.
If Me.lightShapeValue = MarqueeLightShape.Square Then
gSquare.DrawRectangle( _
Pens.Black, _
0, _
0, _
Me.squarePanel.Width - 1, _
Me.squarePanel.Height - 1)
End If
' Draw a filled circle in the client area of
' the circlePanel control.
gCircle.Clear(Me.circlePanel.BackColor)
gCircle.FillEllipse( _
Brushes.Blue, _
0, _
0, _
Me.circlePanel.Width, _
Me.circlePanel.Height)
' If the Circle option has been selected, draw a
' border inside the circlePanel.
If Me.lightShapeValue = MarqueeLightShape.Circle Then
gCircle.DrawRectangle( _
Pens.Black, _
0, _
0, _
Me.circlePanel.Width - 1, _
Me.circlePanel.Height - 1)
End If
Finally
gSquare.Dispose()
End Try
Finally
gCircle.Dispose()
End Try
End Sub
Private Sub squarePanel_Click( _
ByVal sender As Object, _
ByVal e As EventArgs)
Me.lightShapeValue = MarqueeLightShape.Square
Me.Invalidate(False)
Me.editorService.CloseDropDown()
End Sub
Private Sub circlePanel_Click( _
ByVal sender As Object, _
ByVal e As EventArgs)
Me.lightShapeValue = MarqueeLightShape.Circle
Me.Invalidate(False)
Me.editorService.CloseDropDown()
End Sub
#Region "Component Designer generated code"
'/ <summary>
'/ Required method for Designer support - do not modify
'/ the contents of this method with the code editor.
'/ </summary>
Private Sub InitializeComponent()
Me.squarePanel = New System.Windows.Forms.Panel
Me.circlePanel = New System.Windows.Forms.Panel
Me.SuspendLayout()
'
' squarePanel
'
Me.squarePanel.Location = New System.Drawing.Point(8, 10)
Me.squarePanel.Name = "squarePanel"
Me.squarePanel.Size = New System.Drawing.Size(60, 60)
Me.squarePanel.TabIndex = 2
'
' circlePanel
'
Me.circlePanel.Location = New System.Drawing.Point(80, 10)
Me.circlePanel.Name = "circlePanel"
Me.circlePanel.Size = New System.Drawing.Size(60, 60)
Me.circlePanel.TabIndex = 3
'
' LightShapeSelectionControl
'
Me.Controls.Add(squarePanel)
Me.Controls.Add(circlePanel)
Me.Name = "LightShapeSelectionControl"
Me.Size = New System.Drawing.Size(150, 80)
Me.ResumeLayout(False)
End Sub
#End Region
End Class
定义 UI 类型编辑器类
若要实现 UI 类型编辑器行为,应从 UITypeEditor 基类派生。此类名为 LightShapeEditor。
定义 UI 类型编辑器类
1. 通过引用 System.Design 程序集并导入 System.Drawing.Design 和 System.Windows.Forms.Design 命名空间来启用对 .NET Framework 设计时支持的访问。有关更多信息,请参见如何:在 Windows 窗体中访问设计时支持。
2. 在您的 Windows 窗体控件的定义体中,定义 LightShapeEditor 类。
Visual Basic
' This class demonstrates the use of a custom UITypeEditor.
' It allows the MarqueeBorder control's LightShape property
' to be changed at design time using a customized UI element
' that is invoked by the Properties window. The UI is provided
' by the LightShapeSelectionControl class.
Friend Class LightShapeEditor
Inherits UITypeEditor
重写 GetEditStyle 方法
GetEditStyle 方法向设计环境指示您的 UI 类型编辑器实现的是哪种用户界面。UITypeEditorEditStyle 类型中定义可以使用的值。LightShapeEditor 实现一个 DropDown UI 类型编辑器。
重写 GetEditStyle 方法
- 在 LightShapeEditor 定义体中,重写 GetEditStyle 方法以返回 DropDown。
Visual Basic
Public Overrides Function GetEditStyle( _
ByVal context As System.ComponentModel.ITypeDescriptorContext) _
As UITypeEditorEditStyle
Return UITypeEditorEditStyle.DropDown
End Function
重写 EditValue 方法
EditValue 方法为编辑您的自定义类型建立了设计环境和用户界面之间的交互。EditValue 方法创建了一个视图控件或模式对话框的实例,可供用户用来编辑值。用户完成编辑后,EditValue 方法会将值返回给设计环境。
如果是 LightShapeSelectionControl 之类的视图控件,EditValue 方法可能会向视图控件传递一个对 IWindowsFormsEditorService 的引用。当用户选择某个值后,视图控件可以使用此引用来关闭它自己。对于模式对话框,则没有必要这样做,因为窗体可以关闭它自己。
重写 EditValue 方法
- 在 LightShapeEditor 定义体中,重写 EditValue 方法。
Visual Basic
Public Overrides Function EditValue( _
ByVal context As ITypeDescriptorContext, _
ByVal provider As IServiceProvider, _
ByVal value As Object) As Object
If Not (provider Is Nothing) Then
editorService = _
CType(provider.GetService(GetType(IWindowsFormsEditorService)), _
IWindowsFormsEditorService)
End If
If Not (editorService Is Nothing) Then
Dim selectionControl As _
New LightShapeSelectionControl( _
CType(value, MarqueeLightShape), _
editorService)
editorService.DropDownControl(selectionControl)
value = selectionControl.LightShape
End If
Return value
End Function
重写 PaintValue 方法
您可以通过重写 PaintValue 方法来提供您的属性值的图形表示形式。
重写 PaintValue 方法
- 在 LightShapeEditor 定义体中,重写 PaintValue 方法。还要重写 GetPaintValueSupported 方法以返回 true。
Visual Basic
' This method indicates to the design environment that
' the type editor will paint additional content in the
' LightShape entry in the PropertyGrid.
Public Overrides Function GetPaintValueSupported( _
ByVal context As ITypeDescriptorContext) As Boolean
Return True
End Function
' This method paints a graphical representation of the
' selected value of the LightShpae property.
Public Overrides Sub PaintValue( _
ByVal e As PaintValueEventArgs)
Dim shape As MarqueeLightShape = _
CType(e.Value, MarqueeLightShape)
Using p As Pen = Pens.Black
If shape = MarqueeLightShape.Square Then
e.Graphics.DrawRectangle(p, e.Bounds)
Else
e.Graphics.DrawEllipse(p, e.Bounds)
End If
End Using
End Sub
将您的 UI 类型编辑器附加到属性
当您的 UI 类型编辑器可以随时在自定义控件中使用后,将 LightShapeEditor 附加到某个属性,基于 MarqueeLightShape 类型实现此属性,然后对此属性应用 EditorAttribute。
将您的 UI 类型编辑器附加到属性
- 在您的控件定义体中,声明一个名为 LightShape 的 MarqueeLightShape 属性。还需声明一个名为 lightShapeValue、类型为 MarqueeLightShape 的实例字段来支持该属性。对该属性应用 EditorAttribute。
Visual Basic
Private lightShapeValue As MarqueeLightShape
<Category("Marquee"), _
Browsable(True), _
EditorAttribute(GetType(LightShapeEditor), _
GetType(System.Drawing.Design.UITypeEditor))> _
Public Property LightShape() As MarqueeLightShape
Get
Return Me.lightShapeValue
End Get
Set(ByVal value As MarqueeLightShape)
Me.lightShapeValue = value
End Set
End Property
private MarqueeLightShape lightShapeValue;
[Category("Marquee")]
[Browsable(true)]
[EditorAttribute(typeof(LightShapeEditor),
typeof(System.Drawing.Design.UITypeEditor))]
public MarqueeLightShape LightShape
{
get
{
return this.lightShapeValue;
}
set
{
this.lightShapeValue = value;
}
}
测试您的 UI 类型编辑器
通过使用 SelectedObject 属性来创建您的自定义控件的实例并将其附加到 PropertyGrid 控件,您可以测试您的 UI 类型编辑器。
如果您在使用 Visual Studio,则可以创建一个新的 Windows 应用程序项目,引用您的控件的程序集,然后将您的控件的一个实例添加到窗体。Visual Studio 中对此任务提供了广泛的支持。 有关更多信息,请参见演练:使用自定义组件自动填充工具箱。
当您的控件的属性在设计时显示时,您可以选择 LightShape 属性,选中后,会出现一个下拉箭头 ( )。单击此箭头,您的视图控件将出现在属性项下面。单击圆圈或方框,选择值。单击后,视图控件自动关闭,同时您选择的值将出现在 PropertyGrid 中。
注意 |
在开发自定义 UITypeEditor 时,建议将内部版本号设置为随每次生成而递增。这样可以防止在设计环境中创建 UITypeEditor 的较旧的缓存版本。 |