演练:实现 UI 类型编辑器

来源:互联网 发布:学生收费软件 编辑:程序博客网 时间:2024/06/09 09:04

过实现一个用界面 (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

C#

// This defines the possible values for the MarqueeBorder

// control's LightShape property.

public enum MarqueeLightShape

{

    Square,

    Circle

}

 义视图控件

您的自定 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

C#

    // This control provides the custom UI for the LightShape property

    // of the MarqueeBorder. It is used by the LightShapeEditor.

    public class LightShapeSelectionControl : System.Windows.Forms.UserControl

    {

        private MarqueeLightShape lightShapeValue = MarqueeLightShape.Square;

        private IWindowsFormsEditorService editorService = null;

        private System.Windows.Forms.Panel squarePanel;

        private System.Windows.Forms.Panel circlePanel;

       

        // Required designer variable.

        private System.ComponentModel.Container components = null;

 

        // This constructor takes a MarqueeLightShape value from the

        // design-time environment, which will be used to display

        // the initial state.

        public LightShapeSelectionControl(

            MarqueeLightShape lightShape,

            IWindowsFormsEditorService editorService )

        {

            // This call is required by the designer.

            InitializeComponent();

 

            // Cache the light shape value provided by the

            // design-time environment.

            this.lightShapeValue = lightShape;

 

            // Cache the reference to the editor service.

            this.editorService = editorService;

 

            // Handle the Click event for the two panels.

            this.squarePanel.Click += new EventHandler(squarePanel_Click);

            this.circlePanel.Click += new EventHandler(circlePanel_Click);

        }

 

        protected override void Dispose( bool disposing )

        {

            if( disposing )

            {

                // Be sure to unhook event handlers

                // to prevent "lapsed listener" leaks.

                this.squarePanel.Click -=

                    new EventHandler(squarePanel_Click);

                this.circlePanel.Click -=

                    new EventHandler(circlePanel_Click);

 

                if(components != null)

                {

                    components.Dispose();

                }

            }

            base.Dispose( disposing );

        }

 

        // LightShape is the property for which this control provides

        // a custom user interface in the Properties window.

        public MarqueeLightShape LightShape

        {

            get

            {

                return this.lightShapeValue;

            }

           

            set

            {

                if( this.lightShapeValue != value )

                {

                    this.lightShapeValue = value;

                }

            }

        }

 

        protected override void OnPaint(PaintEventArgs e)

        {

            base.OnPaint (e);

 

            using(

                Graphics gSquare = this.squarePanel.CreateGraphics(),

                gCircle = this.circlePanel.CreateGraphics() )

            {   

                // Draw a filled square in the client area of

                // the squarePanel control.

                gSquare.FillRectangle(

                    Brushes.Red,

                    0,

                    0,

                    this.squarePanel.Width,

                    this.squarePanel.Height

                    );

 

                // If the Square option has been selected, draw a

                // border inside the squarePanel.

                if( this.lightShapeValue == MarqueeLightShape.Square )

                {

                    gSquare.DrawRectangle(

                        Pens.Black,

                        0,

                        0,

                        this.squarePanel.Width-1,

                        this.squarePanel.Height-1);

                }

 

                // Draw a filled circle in the client area of

                // the circlePanel control.

                gCircle.Clear( this.circlePanel.BackColor );

                gCircle.FillEllipse(

                    Brushes.Blue,

                    0,

                    0,

                    this.circlePanel.Width,

                    this.circlePanel.Height

                    );

 

                // If the Circle option has been selected, draw a

                // border inside the circlePanel.

                if( this.lightShapeValue == MarqueeLightShape.Circle )

                {

                    gCircle.DrawRectangle(

                        Pens.Black,

                        0,

                        0,

                        this.circlePanel.Width-1,

                        this.circlePanel.Height-1);

                }

            }   

        }

 

        private void squarePanel_Click(object sender, EventArgs e)

        {

            this.lightShapeValue = MarqueeLightShape.Square;

           

            this.Invalidate( false );

           

            this.editorService.CloseDropDown();

        }

 

        private void circlePanel_Click(object sender, EventArgs e)

        {

            this.lightShapeValue = MarqueeLightShape.Circle;

 

            this.Invalidate( false );

 

            this.editorService.CloseDropDown();

        }

 

        #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 void InitializeComponent()

        {

            this.squarePanel = new System.Windows.Forms.Panel();

            this.circlePanel = new System.Windows.Forms.Panel();

            this.SuspendLayout();

//

// squarePanel

//

            this.squarePanel.Location = new System.Drawing.Point(8, 10);

            this.squarePanel.Name = "squarePanel";

            this.squarePanel.Size = new System.Drawing.Size(60, 60);

            this.squarePanel.TabIndex = 2;

//

// circlePanel

//

            this.circlePanel.Location = new System.Drawing.Point(80, 10);

            this.circlePanel.Name = "circlePanel";

            this.circlePanel.Size = new System.Drawing.Size(60, 60);

            this.circlePanel.TabIndex = 3;

//

// LightShapeSelectionControl

//

            this.Controls.Add(this.squarePanel);

            this.Controls.Add(this.circlePanel);

            this.Name = "LightShapeSelectionControl";

            this.Size = new System.Drawing.Size(150, 80);

            this.ResumeLayout(false);

 

        }

        #endregion

 

       

    }

  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

C#

// 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.

internal class LightShapeEditor : 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

 

C#

public override UITypeEditorEditStyle GetEditStyle(

System.ComponentModel.ITypeDescriptorContext context)

{

    return UITypeEditorEditStyle.DropDown;

}

 重写 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

C#

public override object EditValue(

    ITypeDescriptorContext context,

    IServiceProvider provider,

    object value)

{

    if (provider != null)

    {

        editorService =

            provider.GetService(

            typeof(IWindowsFormsEditorService))

            as IWindowsFormsEditorService;

    }

 

    if (editorService != null)

    {

        LightShapeSelectionControl selectionControl =

            new LightShapeSelectionControl(

            (MarqueeLightShape)value,

            editorService);

 

        editorService.DropDownControl(selectionControl);

 

        value = selectionControl.LightShape;

    }

 

    return value;

}

 重写 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

C#

// This method indicates to the design environment that

// the type editor will paint additional content in the

// LightShape entry in the PropertyGrid.

public override bool GetPaintValueSupported(

    ITypeDescriptorContext context)

{ 

    return true;

}

 

// This method paints a graphical representation of the

// selected value of the LightShpae property.

public override void PaintValue(PaintValueEventArgs e)

{  

    MarqueeLightShape shape = (MarqueeLightShape)e.Value;

    using (Pen p = Pens.Black)

    {

        if (shape == MarqueeLightShape.Square)

        {

            e.Graphics.DrawRectangle(p, e.Bounds);

        }

        else

        {

            e.Graphics.DrawEllipse(p, e.Bounds);

        }

    }  

}

 将您的 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

C#

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 旧的存版本。