Поделиться через


Пошаговое руководство. Реализация редактора типов пользовательского интерфейса

Пользовательскую функциональность сложных типов свойств можно создать путем реализации редакторов типов в пользовательском интерфейсе.

В данном пошаговом руководстве описываются способы создания собственного редактора типов пользовательского интерфейса для пользовательского типа и отображения интерфейса редактирования с помощью PropertyGrid.

В этом пошаговом руководстве рассматриваются следующие задачи.

  • Определение настраиваемого типа.

  • Определение элемента управления представления для редактора типов пользовательского интерфейса.

  • Определение класса, производного от класса UITypeEditor.

  • Переопределение метода GetEditStyle для передачи элементу управления PropertyGrid типа стиля редактирования, который будет использовать редактор.

  • Переопределение метода EditValue для обработки пользовательского интерфейса и вводимых данных и присвоения значений.

Сведения о том, как скопировать весь текст кода из этого пошагового руководства, см. в разделе Практическое руководство. Создание элемента управления Windows Forms, в котором используются преимущества функций, применяемых во время разработки.

Обязательные компоненты

Для выполнения этого пошагового руководства потребуется следующее.

  • разрешения, необходимые для создания и выполнения проектов приложений Windows Forms на компьютере, на котором установлена .NET Framework.

Определение настраиваемого типа

Специализированный редактор типов пользовательского интерфейса отображает настраиваемый тип. Этот тип может быть как простым, так и сложным. В данном пошаговом руководстве определяется простой тип с настраиваемым расширением функциональности редактирования во время разработки. Этот тип называется MarqueeLightShape и относится к enum с двумя значениями: Square и Circle.

Определение настраиваемого типа перечисления

  • В основной части определения элемента управления 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
    }
    

Определение элемента управления представления

Специализированный редактор типов пользовательского интерфейса с помощью элемента управления Windows Forms отображает интерфейс редактирования. Этот элемент управления называется LightShapeSelectionControl и является производным от UserControl. Его конструктор принимает текущее значение свойства и ссылку на IWindowsFormsEditorService. Элемент управления представления использует метод CloseDropDown для IWindowsFormsEditorService, чтобы закрыть раскрывающееся окно, когда пользователь щелкает выбранный объект.

Определение элемента управления представления

  • В основной части определения элемента управления 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
    
    
        }
    

Определение класса редактора типов пользовательского интерфейса

Чтобы реализовать расширение функциональности редактора типов пользовательского интерфейса, осуществите наследование от базового класса UITypeEditor. Этот класс называется LightShapeEditor.

Определение класса редактора типов пользовательского интерфейса

  1. Разрешите доступ к поддержке во время разработки для .NET Framework, указав ссылку на сборку System.Design и импортировав пространства имен System.Drawing.Design и System.Windows.Forms.Design. Дополнительные сведения см. в разделе Практическое руководство. Доступ к поддержке во время разработки в Windows Forms.

  2. В основной части определения элемента управления Window 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 уведомляет среду разработки о том, какой тип пользовательского интерфейса реализует редактор типов пользовательского интерфейса. Возможные значения заданы в типе UITypeEditorEditStyle. Класс LightShapeEditor реализует редактор типов пользовательского интерфейса DropDown.

Переопределение метода 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);
            }
        }   
    }
    

Вложение редактора типов пользовательского интерфейса в свойство

Когда редактор типов пользовательского интерфейса готов к использованию в пользовательском элементе управления, вложите LightShapeEditor в свойство, реализуйте свойство, основанное на типе MarqueeLightShape, и примените EditorAttribute к свойству.

Вложение редактора типов пользовательского интерфейса в свойство

  • В основной части определения элемента управления объявите свойство MarqueeLightShape с именем LightShape. Кроме того, объявите поле экземпляра lightShapeValue, имеющее тип MarqueeLightShape, для обратного вызова свойства. Примените 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;
    }
}

Тестирование редактора типов пользовательского интерфейса

Редактор типов пользовательского интерфейса можно протестировать, создав экземпляр пользовательского элемента управления и вложив его в элемент управления PropertyGrid с помощью свойства SelectedObject.

При использовании Visual Studio можно создать новый проект "Приложение Windows", указать ссылку на сборку элемента управления и добавить экземпляр этого элемента управления в форму. В Visual Studio существует расширенная поддержка этой задачи. Дополнительные сведения см. в следующем разделе. Пример. Автоматическое заполнение панели элементов пользовательскими компонентами и Пример. Автоматическое заполнение панели элементов пользовательскими компонентами.

Когда во время разработки отображаются свойства элемента управления, можно выбрать свойство LightShape. При этом отображается стрелка раскрывающегося списка (Стрелка вниз окна свойств). При щелчке по этой стрелке под записью свойства отображается элемент управления представления. Щелкните круг или квадрат для выбора значения. После этого элемент управления представления закрывает себя, а выбранное значение отображается в PropertyGrid.

Примечание

При разработке пользовательского UITypeEditor рекомендуется установить номер сборки, возрастающий после каждого построения.Это предотвращает создание в среде конструирования старых кэшированных версий UITypeEditor.

Следующие действия

После разработки собственного редактора типов пользовательского интерфейса изучите другие способы взаимодействия с PropertyGrid и средой разработки:

См. также

Задачи

Практическое руководство. Создание элемента управления Windows Forms, в котором используются преимущества функций, применяемых во время разработки

Ссылки

UITypeEditor

EditorAttribute

PropertyGrid

Другие ресурсы

Редакторы типов пользовательского интерфейса