チュートリアル : UI 型エディタの実装
更新 : 2007 年 11 月
ユーザー インターフェイス (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 への参照を受け取ります。ビュー コントロールは、IWindowsFormsEditorService で CloseDropDown メソッドを使用して、ユーザーが選択項目をクリックしたときにドロップダウン ウィンドウを閉じます。
ビュー コントロールを定義するには
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 型エディタ クラスを定義するには
System.Design アセンブリを参照し、System.Drawing.Design および System.Windows.Forms.Design 名前空間をインポートして、.NET Framework のデザイン時サポートへのアクセスを有効にします。詳細については、「方法 : Windows フォームでデザイン時サポートにアクセスする」を参照してください。
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 プロパティを選択できます。選択すると、ドロップダウン矢印 () が表示されます。矢印をクリックすると、プロパティ エントリの下にビュー コントロールが表示されます。丸または四角をクリックして値を選択します。クリックするとビュー コントロールは消え、選択した値が PropertyGrid に表示されます。
メモ : |
---|
カスタムの UITypeEditor を開発する場合は、ビルド番号をビルドごとにインクリメントすることをお勧めします。これによって、UITypeEditor のキャッシュされた古いバージョンがデザイン環境に作成されることを防止できます。 |
次の手順
独自の UI 型エディタを作成した後は、PropertyGrid およびデザイン環境と対話する次のような方法を試します。
ビュー コントロールの代わりにモーダル ダイアログに基づいて、UI 型エディタを記述します。
TypeConverter クラスを使用して、カスタム型の型コンバータを記述します。詳細については、「方法 : 型コンバータを実装する」を参照してください。
カスタム コントロールのデザイナを記述します。詳細については、「方法 : デザイン時機能を活用した Windows フォーム コントロールを作成する」を参照してください。
参照
処理手順
方法 : デザイン時機能を活用した Windows フォーム コントロールを作成する