チュートリアル : UI 型エディターの実装

ユーザー インターフェイス (UI) 型エディターを実装すると、複雑なプロパティの型に対してカスタムのデザイン時の操作を提供できます。

このチュートリアルでは、PropertyGrid を使用してカスタム型用に独自の UI 型エディターを作成し、編集用のインターフェイスを表示する方法について説明します。

このチュートリアルでは、以下のタスクについて説明します。

  • カスタム型を定義します。

  • UI 型エディターのビュー コントロールを定義します。

  • UITypeEditor から派生するクラスを定義します。

  • GetEditStyle メソッドをオーバーライドして、エディターが使用するエディター スタイルの種類を PropertyGrid に通知します。

  • EditValue メソッドをオーバーライドして、ユーザー インターフェイス、ユーザー入力の処理、および値の割り当てを処理します。

このチュートリアルのコードを単一のリストとしてコピーするには、「方法 : デザイン時機能を活用した Windows フォーム コントロールを作成する」を参照してください。

必須コンポーネント

このチュートリアルを完了するための要件は次のとおりです。

  • .NET Framework がインストールされているコンピューターで Windows フォーム アプリケーション プロジェクトを作成および実行するために必要なアクセス許可。

カスタム型の定義

カスタムの UI 型エディターには、カスタム型が表示されます。 この型は、複雑な場合も単純な場合もあります。 このチュートリアルでは、カスタムのデザイン時編集動作を備えた単純型を定義します。 この型は MarqueeLightShape と呼ばれます。これは、Square と Circle の 2 つの値を持つ enum です。

カスタムの列挙型を定義するには

  • Windows フォーム コントロールの定義の本体で、MarqueeLightShape 型を定義します。

    ' This defines the possible values for the MarqueeBorder 
    ' control's LightShape property. 
    Public Enum MarqueeLightShape
        Square
        Circle
    End Enum
    
    // This defines the possible values for the MarqueeBorder 
    // control's LightShape property. 
    public enum MarqueeLightShape
    {
        Square,
        Circle
    }
    

ビュー コントロールの定義

カスタムの UI 型エディターには、Windows フォーム コントロールを使用して編集用のインターフェイスが表示されます。 このコントロールは LightShapeSelectionControl と呼ばれ、UserControl から派生します。 そのコンストラクターは現在のプロパティ値および IWindowsFormsEditorService への参照を受け取ります。 ビュー コントロールは、IWindowsFormsEditorServiceCloseDropDown メソッドを使用して、ユーザーが選択項目をクリックしたときにドロップダウン ウィンドウを閉じます。

ビュー コントロールを定義するには

  • Windows フォーム コントロールの定義の本体で、LightShapeSelectionControl コントロールを定義します。

    ' 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 (components IsNot 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
    
        // 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 クラスを定義します。

    ' 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
    
    // 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 を返します。

            Public Overrides Function GetEditStyle( _
            ByVal context As System.ComponentModel.ITypeDescriptorContext) _
            As UITypeEditorEditStyle
                Return UITypeEditorEditStyle.DropDown
            End Function
    
    public override UITypeEditorEditStyle GetEditStyle(
    System.ComponentModel.ITypeDescriptorContext context)
    {
        return UITypeEditorEditStyle.DropDown;
    }
    

EditValue メソッドのオーバーライド

EditValue メソッドは、デザイン環境とカスタム型を編集するためのユーザー インターフェイスの間に対話を確立します。 EditValue メソッドは、ユーザーが値を編集するビュー コントロールまたはモーダル ダイアログ ボックスのインスタンスを作成します。 ユーザーが編集を終えると、EditValue メソッドは値をデザイン環境に返します。

LightShapeSelectionControl などのビュー コントロールの場合、EditValue メソッドは IWindowsFormsEditorService への参照をビュー コントロールに渡すことがあります。 ビュー コントロールはこの参照を使用して、ユーザーが値を選択したときにそれ自体を閉じることができます。 モーダル ダイアログ ボックスではフォームがそれ自体を閉じることができるので、これは不要です。

EditValue メソッドをオーバーライドするには

  • LightShapeEditor の定義の本体で、EditValue メソッドをオーバーライドします。

    Public Overrides Function EditValue( _
    ByVal context As ITypeDescriptorContext, _
    ByVal provider As IServiceProvider, _
    ByVal value As Object) As Object 
        If (provider IsNot Nothing) Then
            editorService = _
            CType(provider.GetService(GetType(IWindowsFormsEditorService)), _
            IWindowsFormsEditorService)
        End If 
    
        If (editorService IsNot Nothing) Then 
            Dim selectionControl As _
            New LightShapeSelectionControl( _
            CType(value, MarqueeLightShape), _
            editorService)
    
            editorService.DropDownControl(selectionControl)
    
            value = selectionControl.LightShape
        End If 
    
        Return value
    End Function
    
    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 を返します。

    ' 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
    
    // 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 プロパティを宣言します。 また、プロパティを返すために、MarqueeLightShape 型の lightShapeValue という名前のインスタンス フィールドを宣言します。 EditorAttribute をプロパティに適用します。
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 型エディターのテスト

UI 型エディターをテストするには、カスタム コントロールのインスタンスを作成し、SelectedObject プロパティを使用して PropertyGrid コントロールにアタッチします。

Visual Studio を使用している場合は、新しい Windows アプリケーション プロジェクトを作成し、コントロールのアセンブリを参照し、コントロールのインスタンスをフォームに追加します。 Visual Studio では、このタスクに対する広範なサポートが用意されています。 チュートリアル : ツールボックスへのカスタム コンポーネントの自動設定
チュートリアル : ツールボックスへのカスタム コンポーネントの自動設定
チュートリアル : ツールボックスへのカスタム コンポーネントの自動設定
チュートリアル : ツールボックスへのカスタム コンポーネントの自動設定

コントロールのプロパティがデザイン時に表示され、LightShape プロパティを選択できます。 選択すると、ドロップダウン矢印 (Properties Window Down Arrow) が表示されます。 矢印をクリックすると、プロパティ エントリの下にビュー コントロールが表示されます。 丸または四角をクリックして値を選択します。 クリックするとビュー コントロールは消え、選択した値が PropertyGrid に表示されます。

注意

カスタムの UITypeEditor を開発する場合は、ビルド番号をビルドごとにインクリメントすることをお勧めします。これによって、UITypeEditor のキャッシュされた古いバージョンがデザイン環境に作成されることを防止できます。

次の手順

独自の UI 型エディターを作成した後は、PropertyGrid およびデザイン環境と対話する次のような方法を試します。

参照

処理手順

方法 : デザイン時機能を活用した Windows フォーム コントロールを作成する

関連項目

UITypeEditor

EditorAttribute

PropertyGrid

その他の技術情報

ユーザー インターフェイス型エディター