Share via


연습: UI 형식 편집기 구현

UI(사용자 인터페이스) 형식 편집기를 구현하여 복잡한 속성 형식에 대한 사용자 지정 디자인 타임 환경을 제공할 수 있습니다.

이 연습에서는 PropertyGrid를 사용하여 자신만의 UI 형식 편집기에서 사용자 지정 형식을 작성하고 편집 인터페이스를 표시하는 방법을 설명합니다.

이 연습에서 수행할 작업은 다음과 같습니다.

  • 사용자 지정 형식 정의

  • UI 형식 편집기의 뷰 컨트롤 정의

  • UITypeEditor에서 파생되는 클래스 정의

  • 편집기에서 사용할 편집기 스타일 형식을 PropertyGrid에 알려 주는 GetEditStyle 메서드 재정의

  • 사용자 인터페이스, 사용자 입력 처리 및 값 할당을 처리하는 EditValue 메서드 재정의

이 연습의 코드를 단일 목록으로 복사하려면 방법: 디자인 타임 기능을 활용하는 Windows Forms 컨트롤 만들기를 참조하십시오.

사전 요구 사항

이 연습을 완료하려면 다음과 같은 요건이 필요합니다.

  • .NET Framework가 설치된 컴퓨터에서 Windows Forms 응용 프로그램 프로젝트를 만들고 실행할 수 있는 충분한 권한

사용자 지정 형식 정의

사용자 지정 UI 형식 편집기에서는 사용자 지정 형식을 표시합니다. 이 형식은 복잡하거나 단순할 수 있습니다. 이 연습에서는 사용자 지정 디자인 타임 편집 동작을 사용하여 단순 형식을 정의합니다. 이 형식은 MarqueeLightShape라고 하며 Square 및 Circle이라는 두 개의 값을 가진 enum입니다.

사용자 지정 열거형을 정의하려면

  • Windows Forms 컨트롤 정의 본문에 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 Forms 컨트롤을 사용하여 편집 인터페이스를 표시합니다. 이 컨트롤은 이름이 LightShapeSelectionControl이고 UserControl에서 파생됩니다. 이 컨트롤의 생성자는 IWindowsFormsEditorService에 대한 현재 속성 값과 참조를 가져옵니다. 뷰 컨트롤은 IWindowsFormsEditorServiceCloseDropDown 메서드를 사용하여 사용자가 선택에서 클릭할 때 드롭다운 창을 닫습니다.

뷰 컨트롤을 정의하려면

  • Windows Forms 컨트롤 정의 본문에 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.DesignSystem.Windows.Forms.Design 네임스페이스를 가져와 .NET Framework 디자인 타임 지원에 액세스할 수 있도록 합니다. 자세한 내용은 방법: Windows Forms에서 디자인 타임 지원 액세스를 참조하십시오.

  2. IWindow Forms 컨트롤 정의 본문에 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 정의 본문에 DropDown을 반환하도록 GetEditStyle 메서드를 재정의합니다.

            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 메서드를 재정의합니다. 또한 true를 반환하도록 GetPaintValueSupported 메서드를 재정의합니다.

    ' 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 형식 편집기 테스트

사용자 지정 컨트롤의 인스턴스를 만들고 SelectedObject 속성을 통해 이를 PropertyGrid 컨트롤에 연결하여 UI 형식 편집기를 테스트합니다.

Visual Studio를 사용하고 있는 경우 새 Windows 응용 프로그램 프로젝트를 만들고 컨트롤 어셈브리를 참조한 다음 컨트롤의 인스턴스를 폼에 추가할 수 있습니다. Visual Studio에서는 이 작업이 폭넓게 지원됩니다. 연습: 도구 상자에 자동으로 사용자 지정 구성 요소 채우기
연습: 도구 상자에 자동으로 사용자 지정 구성 요소 채우기
연습: 도구 상자에 자동으로 사용자 지정 구성 요소 채우기
연습: 도구 상자에 자동으로 사용자 지정 구성 요소 채우기

디자인 타임에 컨트롤의 속성이 표시되면 LightShape 속성을 선택할 수 있습니다. 선택하면 드롭다운 화살표(Properties Window Down Arrow)가 나타납니다. 화살표를 클릭하면 뷰 컨트롤이 속성 항목 아래에 표시됩니다. 원이나 사각형을 클릭하여 값을 선택합니다. 클릭하면 뷰 컨트롤이 닫히고 선택한 값이 PropertyGrid에 나타납니다.

참고

사용자 지정 UITypeEditor를 개발하는 경우 빌드가 발생할 때마다 증가하도록 빌드 번호를 설정하는 것이 좋습니다.그러면 이전의 캐시된 버전의 UITypeEditor가 디자인 환경에서 만들어지지 못하도록 할 수 있습니다.

다음 단계

사용자 고유의 UI 형식 편집기를 작성했으면 PropertyGrid 및 디자인 환경과 상호 작용할 수 있는 다른 방법을 탐색합니다.

참고 항목

작업

방법: 디자인 타임 기능을 활용하는 Windows Forms 컨트롤 만들기

참조

UITypeEditor

EditorAttribute

PropertyGrid

기타 리소스

사용자 인터페이스 형식 편집기