型コンバータの実装
型コンバータを使用することによって、値のデータ型を変換できます。テキストから値への変換や、値を選択するためのドロップダウン リストが提供されるため、デザイン時のプロパティ構成を簡単に行うことができます。型コンバータは、適切に構成されている場合、InstanceDescriptor オブジェクトと System.Reflection オブジェクトを使用してプロパティ構成コードを生成し、実行時にプロパティを初期化するコードの生成に必要な情報を、デザイナのシリアル化システムに提供します。
値を変換するための型コンバータ
型コンバータを使用すると、デザイン時と実行時に、文字列から値への変換や、サポートされているデータ型の変換を実行できます。フォーム デザイナのプロパティ ブラウザなどのホストでは、型コンバータを使用することで、プロパティ値をユーザーに対してテキストとして表示したり、ユーザーが入力したテキストを適切なデータ型の値に変換したりできます。
ほとんどのネイティブ データ型 (Int32、String、列挙型など) には既定の型コンバータがあり、このコンバータによって文字列から値への変換や検証が実行されます。既定の型コンバータは TypeConverterNameConverter という名前で System.ComponentModel 名前空間に含まれています。既定の機能では不十分な場合は型コンバータを拡張できます。また、型コンバータが関連付けられていないカスタム型を定義した場合は、カスタムの型コンバータを実装できます。
**メモ **TypeConverterAttribute 属性は、一般にプロパティやデータ メンバに適用され、型コンバータに関連付けられます。TypeConverterAttribute 属性が型に適用されている場合、その型のプロパティやデータ メンバにこの属性を再適用する必要はありません。
型コンバータの実装は、ユーザー インターフェイスの機能には依存しません。したがって、Windows フォームと Web フォームで同じ型コンバータを適用できます。
文字列を Point に変換できる単純な型コンバータを実装するには
- System.ComponentModel.TypeConverter. の派生クラスを定義します。
- 型コンバータで変換できる変換元の型を指定する CanConvertFrom メソッドをオーバーライドします。このメソッドはオーバーロードされます。
- 変換を実装する ConvertFrom メソッドをオーバーライドします。このメソッドはオーバーロードされます。
- 型コンバータで変換できる変換後の型を指定する CanConvertTo メソッドをオーバーライドします。文字列型に変換する場合は、このメソッドをオーバーライドする必要はありません。このメソッドはオーバーロードされます。
- 変換を実装する ConvertTo メソッドをオーバーライドします。このメソッドはオーバーロードされます。
- 検証を実行する IsValid メソッドをオーバーライドします。このメソッドはオーバーロードされます。
String 型を System.Drawing.Point 型に変換し、System.Drawing.Point 型を String 型に変換する型コンバータを実装するコード例を次に示します。この例では、CanConvertTo メソッドと IsValid メソッドはオーバーライドされません。
Option Explicit
Option Strict
Imports System
Imports System.ComponentModel
Imports System.Globalization
Imports System.Drawing
Public Class PointConverter
Inherits TypeConverter
' Overrides the CanConvertFrom method of TypeConverter.
' The ITypeDescriptorContext interface provides the context for the
' conversion. Typically, this interface is used at design time to
' provide information about the design-time container.
Public Overrides Overloads Function CanConvertFrom(context As ITypeDescriptorContext, sourceType As Type) As Boolean
If sourceType Is GetType(String) Then
Return True
End If
Return MyBase.CanConvertFrom(context, sourceType)
End Function
' Overrides the ConvertFrom method of TypeConverter.
Public Overrides Overloads Function ConvertFrom(context As ITypeDescriptorContext, culture As CultureInfo, value As Object) As Object
If TypeOf value Is String Then
Dim v As String() = CStr(value).Split(New Char() {","c})
Return New Point(Integer.Parse(v(0)), Integer.Parse(v(1)))
End If
Return MyBase.ConvertFrom(context, culture, value)
End Function
' Overrides the ConvertTo method of TypeConverter.
Public Overrides Overloads Function ConvertTo(context As ITypeDescriptorContext, culture As CultureInfo, value As Object, destinationType As Type) As Object
If destinationType Is GetType(String) Then
Return CType(value, Point).X & "," & CType(value, Point).Y
End If
Return MyBase.ConvertTo(context, culture, value, destinationType)
End Function
End Class
[C#]
using System;
using System.ComponentModel;
using System.Globalization;
using System.Drawing;
public class PointConverter : TypeConverter {
// Overrides the CanConvertFrom method of TypeConverter.
// The ITypeDescriptorContext interface provides the context for the
// conversion. Typically, this interface is used at design time to
// provide information about the design-time container.
public override bool CanConvertFrom(ITypeDescriptorContext context,
Type sourceType) {
if (sourceType == typeof(string)) {
return true;
}
return base.CanConvertFrom(context, sourceType);
}
// Overrides the ConvertFrom method of TypeConverter.
public override object ConvertFrom(ITypeDescriptorContext context,
CultureInfo culture, object value) {
if (value is string) {
string[] v = ((string)value).Split(new char[] {','});
return new Point(int.Parse(v[0]), int.Parse(v[1]));
}
return base.ConvertFrom(context, culture, value);
}
// Overrides the ConvertTo method of TypeConverter.
public override object ConvertTo(ITypeDescriptorContext context,
CultureInfo culture, object value, Type destinationType) {
if (destinationType == typeof(string)) {
return ((Point)value).X + "," + ((Point)value).Y;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
プロパティ グリッドに標準値のリストを提供する型コンバータ
型コンバータで、プロパティ グリッド コントロールの型に応じた値のリストを提供できます。型コンバータが型の標準値のセットを提供する場合、プロパティ グリッド コントロール内の関連付けられた型のプロパティの値入力フィールドには、クリックしたときにプロパティの値として設定するための値の一覧を表示する下向きの矢印が表示されます。
この型コンバータが関連付けられている型のプロパティをデザイン時環境のプロパティ ブラウザで選択した場合、値入力フィールドにはボタンが表示されます。このボタンは、プロパティの型の標準値をドロップダウン リストで表示し、値を選択できるようにします。
プロパティ ブラウザで標準値のドロップダウン リストを提供する単純な型コンバータを実装するには
- System.ComponentModel.TypeConverter の派生クラスを定義します。
- GetStandardValuesSupported メソッドをオーバーライドし、true を返します。
- GetStandardValues メソッドをオーバーライドし、プロパティの型の標準値を格納する StandardValuesCollection を返します。プロパティの型の標準値は、文字列型である必要があります。
- CanConvertFrom メソッドをオーバーライドし、sourceType パラメータが文字列型だったら true を返します。
- ConvertFrom メソッドをオーバーライドし、value パラメータに基づいてプロパティの適切な値を返します。
- 型コンバータの型を示す TypeConverterAttribute を、標準値のセットを提供する型に適用します。
型コンバータが関連付けられている型のプロパティのプロパティ グリッド コントロールに、標準値のリストを提供する型コンバータの例を次に示します。この例の型コンバータは、関連付けられている整数型のプロパティをサポートします。Visual Studio .NET でこの例を使用するには、コードをコンパイルしてクラス ライブラリを作成し、IntStandardValuesControl コンポーネントをツールボックスに追加します。デザイン モードのフォームに IntStandardValuesControl のインスタンスを追加し、このコントロールを選択した状態で、[プロパティ] ウィンドウをスクロールして TestInt
プロパティを表示します。このプロパティの値入力フィールドを選択すると、下向きの矢印が表示され、クリックすると標準値のドロップダウン リストが表示されます。整数値を入力すると、その値が標準値のリストに追加され、プロパティは指定した値に設定されます。
using System;
using System.ComponentModel;
using System.Collections;
using System.Drawing;
using System.Windows.Forms;
namespace StandardValuesTest
{
public class StandardValuesIntConverter : System.ComponentModel.TypeConverter
{
private ArrayList values;
public StandardValuesIntConverter()
{
// Initializes the standard values list with defaults.
values = new ArrayList(new int[] { 1, 2, 3, 4, 5 });
}
// Indicates this converter provides a list of standard values.
public override bool GetStandardValuesSupported(System.ComponentModel.ITypeDescriptorContext context)
{
return true;
}
// Returns a StandardValuesCollection of standard value objects.
public override System.ComponentModel.TypeConverter.StandardValuesCollection GetStandardValues(System.ComponentModel.ITypeDescriptorContext context)
{
// Passes the local integer array.
StandardValuesCollection svc =
new StandardValuesCollection(values);
return svc;
}
// Returns true for a sourceType of string to indicate that
// conversions from string to integer are supported. (The
// GetStandardValues method requires a string to native type
// conversion because the items in the drop-down list are
// translated to string.)
public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
{
if( sourceType == typeof(string) )
return true;
else
return base.CanConvertFrom(context, sourceType);
}
// If the type of the value to convert is string, parses the string
// and returns the integer to set the value of the property to.
// This example first extends the integer array that supplies the
// standard values collection if the user-entered value is not
// already in the array.
public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if( value.GetType() == typeof(string) )
{
// Parses the string to get the integer to set to the property.
int newVal = int.Parse((string)value);
// Tests whether new integer is already in the list.
if( !values.Contains(newVal) )
{
// If the integer is not in list, adds it in order.
values.Add(newVal);
values.Sort();
}
// Returns the integer value to assign to the property.
return newVal;
}
else
return base.ConvertFrom(context, culture, value);
}
}
// Provides a test control with an integer property associated with
// the StandardValuesIntConverter type converter.
public class IntStandardValuesControl : System.Windows.Forms.UserControl
{
[TypeConverter(typeof(StandardValuesIntConverter))]
public int TestInt
{
get
{
return this.integer_field;
}
set
{
if(value.GetType() == typeof(int))
this.integer_field = value;
}
}
private int integer_field = 0;
public IntStandardValuesControl()
{
this.BackColor = Color.White;
this.Size = new Size(472, 80);
}
// OnPaint override displays instructions for the example.
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
if(this.DesignMode)
{
e.Graphics.DrawString("TypeConverter.GetStandardValues Example Control", new Font(FontFamily.GenericMonospace, 10), new SolidBrush(Color.Blue), 5, 5);
e.Graphics.DrawString("The type converter for the TestInt property of this", new Font(FontFamily.GenericMonospace, 10), new SolidBrush(Color.Black), 5, 20);
e.Graphics.DrawString("component provides a list of standard values to the", new Font(FontFamily.GenericMonospace, 10), new SolidBrush(Color.Black), 5, 30);
e.Graphics.DrawString("Properties window. Setting a value through a property", new Font(FontFamily.GenericMonospace, 10), new SolidBrush(Color.Black), 5, 40);
e.Graphics.DrawString("grid adds it to the list of standard values.", new Font(FontFamily.GenericMonospace, 10), new SolidBrush(Color.Black), 5, 50);
}
else
{
e.Graphics.DrawString("TypeConverter.GetStandardValues Example Control", new Font(FontFamily.GenericMonospace, 10), new SolidBrush(Color.Blue), 5, 5);
e.Graphics.DrawString("This control was intended for use in design mode.", new Font(FontFamily.GenericMonospace, 10), new SolidBrush(Color.Black), 5, 20);
}
}
}
}
[Visual Basic]
Imports System
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Collections
Imports System.Drawing
Imports System.Windows.Forms
Namespace StandardValuesTest
Public Class StandardValuesIntConverter
Inherits System.ComponentModel.TypeConverter
Private values As ArrayList
Public Sub New()
' Initializes the standard values list with defaults.
values = New ArrayList(New Integer() {1, 2, 3, 4, 5})
End Sub 'New
' Indicates this type converter provides a list of standard values.
Public Overloads Overrides Function GetStandardValuesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
Return True
End Function 'GetStandardValuesSupported
' Returns a StandardValuesCollection of standard value objects.
Public Overloads Overrides Function GetStandardValues(ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.ComponentModel.TypeConverter.StandardValuesCollection
' Passes the local integer array.
Dim svc As New StandardValuesCollection(values)
Return svc
End Function 'GetStandardValues
' Returns true for a sourceType of string to indicate that
' conversions from string to integer are supported. (The
' GetStandardValues method requires a string to native type
' conversion because the items in the drop-down list are
' translated to string.)
Public Overloads Overrides Function CanConvertFrom(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal sourceType As System.Type) As Boolean
If sourceType Is GetType(String) Then
Return True
Else
Return MyBase.CanConvertFrom(context, sourceType)
End If
End Function 'CanConvertFrom
' If the type of the value to convert is string, parses the string
' and returns the integer to set the value of the property to.
' This example first extends the integer array that supplies the
' standard values collection if the user-entered value is not
' already in the array.
Public Overloads Overrides Function ConvertFrom(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal culture As System.Globalization.CultureInfo, ByVal value As Object) As Object
If value.GetType() Is GetType(String) Then
' Parses the string to get the integer to set to the property.
Dim newVal As Integer = Integer.Parse(CStr(value))
' Tests whether new integer is already in the list.
If Not values.Contains(newVal) Then
' If the integer is not in list, adds it in order.
values.Add(newVal)
values.Sort()
End If
' Returns the integer value to assign to the property.
Return newVal
Else
Return MyBase.ConvertFrom(context, culture, value)
End If
End Function 'ConvertFrom
End Class 'StandardValuesIntConverter
' Provides a test control with an integer property associated with the
' StandardValuesIntConverter type converter.
Public Class IntStandardValuesControl
Inherits System.Windows.Forms.UserControl
<TypeConverter(GetType(StandardValuesIntConverter))> _
Public Property TestInt() As Integer
Get
Return Me.integer_field
End Get
Set(ByVal Value As Integer)
If Value.GetType() Is GetType(Integer) Then
Me.integer_field = Value
End If
End Set
End Property
Private integer_field As Integer = 0
Public Sub New()
Me.BackColor = Color.White
Me.Size = New Size(472, 80)
End Sub 'New
' OnPaint override displays instructions for the example.
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
If Me.DesignMode Then
e.Graphics.DrawString("TypeConverter.GetStandardValues Example Control", New Font(FontFamily.GenericMonospace, 10), New SolidBrush(Color.Blue), 5, 5)
e.Graphics.DrawString("The type converter for the TestInt property of this", New Font(FontFamily.GenericMonospace, 10), New SolidBrush(Color.Black), 5, 20)
e.Graphics.DrawString("component provides a list of standard values to the", New Font(FontFamily.GenericMonospace, 10), New SolidBrush(Color.Black), 5, 30)
e.Graphics.DrawString("Properties window. Setting a value through a property", New Font(FontFamily.GenericMonospace, 10), New SolidBrush(Color.Black), 5, 40)
e.Graphics.DrawString("grid adds it to the list of standard values.", New Font(FontFamily.GenericMonospace, 10), New SolidBrush(Color.Black), 5, 50)
Else
e.Graphics.DrawString("TypeConverter.GetStandardValues Example Control", New Font(FontFamily.GenericMonospace, 10), New SolidBrush(Color.Blue), 5, 5)
e.Graphics.DrawString("This control was intended for use in design mode.", New Font(FontFamily.GenericMonospace, 10), New SolidBrush(Color.Black), 5, 20)
End If
End Sub 'OnPaint
End Class 'IntStandardValuesControl
End Namespace 'StandardValuesTest
実行時にプロパティを初期化するコードを生成する型コンバータ
.NET Framework には、実行時にプロパティを初期化するための、動的に構成できるプロパティ初期化コードをデザイン時に生成する機能が用意されています。
開発者は、コンストラクタ ベースの初期化コードを生成する型コンバータを作成できます。このような型コンバータでは、実行時に型のプロパティを構成するために、デザイン時に設定された値を使用して動的にコンストラクタ コードを生成できます。型コンバータは、プロパティのコンストラクタの型と値を構成するロジックを実装します。
コンストラクタ以外で、プロパティを初期化するコードを生成する必要がある場合は、カスタムの CodeDomSerializer を実装し、その CodeDomSerializer を特定の型に関連付ける DesignerSerializerAttribute を適用することによって、動的にコードを生成できます。この方法は、通常、コンポーネントを初期化するためのコードの生成を動的に制御またはカスタマイズする必要がある場合にだけ使用されます。この方法の詳細については、CodeDomSerializer の説明を参照してください。
カスタム コンストラクタ ベースのプロパティ初期化子を構築するには、型コンバータを、初期化するプロパティの型に関連付ける必要があり、型コンバータは InstanceDescriptor に変換できる必要があります。
コンストラクタ ベースのプロパティ初期化コードを生成する型コンバータを実装するには
- System.ComponentModel.TypeConverter の派生クラスを定義します。
- CanConvertTo メソッドをオーバーライドします。destinationType パラメータが InstanceDescriptor 型である場合は、true を返します。
- ConvertTo メソッドをオーバーライドします。destinationType パラメータが InstanceDescriptor 型である場合は、コードを生成するコンストラクタとコンストラクタの引数を表す InstanceDescriptor を構築し、返します。適切なコンストラクタとパラメータを表す InstanceDescriptor を作成するには、初期化するプロパティの Type から ConstructorInfo を取得します。ConstructorInfo を取得するには、目的のコンストラクタの適切なメソッド シグネチャを使って GetConstructor メソッドまたは GetConstructors メソッドを呼び出します。次に、新しいインスタンス記述子を作成し、使用するコンストラクタの型を表す ConstructorInfo と、コンストラクタのシグネチャに一致するパラメータ オブジェクトの配列を渡します。
Point 型のプロパティに対するコンストラクタ ベースのプロパティ初期化コードを生成できる型コンバータを実装する例を次に示します。
public class PointConverter : TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(InstanceDescriptor))
return true;
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context,
CultureInfo culture, object value, Type destinationType)
{
// Insert other ConvertTo operations here.
//
if (destinationType == typeof(InstanceDescriptor) &&
value is Point)
{
Point pt = (Point)value;
ConstructorInfo ctor = typeof(Point).GetConstructor(
new Type[] {typeof(int), typeof(int)});
if (ctor != null)
{
return new InstanceDescriptor(ctor, new object[] {pt.X, pt.Y});
}
}
return base.ConvertTo(context, culture, value, destinationType);
}