Пошаговое руководство. Реализация редактора типов пользовательского интерфейса
Обновлен: Ноябрь 2007
Пользовательскую функциональность сложных типов свойств можно создать путем реализации редакторов типов в пользовательском интерфейсе.
В данном пошаговом руководстве описываются способы создания собственного редактора типов пользовательского интерфейса для пользовательского типа и отображения интерфейса редактирования с помощью 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.
Определение класса редактора типов пользовательского интерфейса
Разрешите доступ к поддержке во время разработки для .NET Framework, указав ссылку на сборку System.Design и импортировав пространства имен System.Drawing.Design и System.Windows.Forms.Design. Дополнительные сведения см. в разделе Практическое руководство. Доступ к поддержке во время разработки в Windows Forms.
В основной части определения элемента управления 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 и средой разработки:
Разработайте редактор типов пользовательского интерфейса, основанный не на элементе управления представления, а на модальном диалоговом окне.
Разработайте преобразователь типов для настраиваемого типа с помощью класса TypeConverter. Дополнительные сведения см. в разделе Практическое руководство. Реализация преобразователя типов.
Разработайте конструктор для пользовательского элемента управления. Дополнительные сведения см. в разделе Практическое руководство. Создание элемента управления Windows Forms, в котором используются преимущества функций, применяемых во время разработки.