演練:實現 UI 類型編輯器

過實現一個用界面 (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 舊的存版本。

發佈了25 篇原創文章 · 獲贊 1 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章