TypeConverterその他の機能

カスタムコントロール作成入門講座中級編

ShadowクラスのDirectionプロパティは列挙型です。そして、列挙型の場合は、プロパティウィンドウでドロップダウンコンボボックスで選択することができます。実は、このドロップダウン、任意の型で使用することができます。

例として、ShadowクラスのDepthプロパティに実装してみましょう。Depthはint型なので、Int32Converterを継承したType Converterを作ります。

public class ShadowDepthConverter : Int32Converter
{
    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
    {
        return true;
    }

    public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
    {
        return false;
    }

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        int[] values = new int[] { 1, 2, 3, 4, 5 };
        return new StandardValuesCollection(values);
    }
}
Public Class ShadowDepthConverter : Inherits Int32Converter
    Public Overrides Function GetStandardValuesSupported(context As ITypeDescriptorContext) As Boolean
        Return True
    End Function

    Public Overrides Function GetStandardValuesExclusive(context As ITypeDescriptorContext) As Boolean
        Return False
    End Function

    Public Overrides Function GetStandardValues(context As ITypeDescriptorContext) As StandardValuesCollection
        Dim values As Integer() = New Integer() {1, 2, 3, 4, 5}
        Return New StandardValuesCollection(values)
    End Function
End Class

ドロップダウンの機能を有効にするにはGetStandardValuesSupportedでtrueを返します。GetStandardValuesExclusiveは、ドロップダウンの中の値以外を受け付けないようにする時にtrueを返します。Depthではこの制限がないのでfalseを返しています。GetStandardValuesで、ドロップダウンに表示する項目を設定して返します。

もしドロップダウンの中の値を文字列にしたい場合は、StringConverterを継承して、GetStandardValuesでstringの配列を使用するようにします。

後は、DepthプロパティにこのType Converterを使うように指示するだけです。

public class Shadow
{
    ...
    [DefaultValue(1)]
    [TypeConverter(typeof(ShadowDepthConverter))]
    public int Depth { get; set; }
}
Public Class Shadow
    ...
    <DefaultValue(1)> _
    <TypeConverter(GetType(ShadowDepthConverter))> _
    Public Property Depth() As Integer = 1
End Class

簡単ですね。もっと複雑な編集方法を提供したい場合は、カスタムプロパティエディタを作れば可能になりますが、それは次回以降に紹介します。

※※※以下は未解決情報です※※※

C#でInitializeComponentを見てみると、次のようになっています。

private void InitializeComponent()
{
    this.customControl11 = new ClassLibrary1.CustomControl1();
    this.SuspendLayout();
    // 
    // customControl11
    // 
    this.customControl11.Font = new System.Drawing.Font("MS UI Gothic", 20F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
    this.customControl11.ForeColor = System.Drawing.Color.Coral;
    this.customControl11.Location = new System.Drawing.Point(2, 2);
    this.customControl11.Name = "customControl11";
    this.customControl11.Color = System.Drawing.Color.Black;
    this.customControl11.Depth = 8;
    this.customControl11.Shadow.Direction = ClassLibrary1.ShadowDirection.ToTopLeft;
    this.customControl11.Shadow = shadow1;
    this.customControl11.Size = new System.Drawing.Size(150, 86);
    this.customControl11.TabIndex = 1;
    this.customControl11.Text = "影付き文字";

Shadowの各項目が1つ1つ初期化されていますね。では、3つの項目を同時に初期化したい場合にはどうすればいいでしょうか。次のようにShadowも、SizeやFontと同じような初期化の仕方ができれば、それが可能になるはずです。

    this.customControl11.Shadow = new ClassLibrary1.Shadow(System.Drawing.Color.Black, 8, ClassLibrary1.ShadowDirection.ToTopLeft);

そのためにはまず、3つの引数を持つコンストラクターを作ります。

public Shadow(Color color, int depth, ShadowDirection direction)
{
    Color = color;
    Depth = depth;
    Direction = direction;
}
Public Sub New(color_ As Color, depth_ As Integer, direction_ As ShadowDirection)
	Color = color_
	Depth = depth_
	Direction = direction_
End Sub

続いて、このコンストラクターを使うように、TypeConverterに変更を加えますが、先にusing/Importsを指定します。

using System.ComponentModel.Design.Serialization;
using System.Reflection;
Imports System.ComponentModel.Design.Serialization
Imports System.Reflection

そして、CanConvertToとConvertToを、InstanceDescriptorに対応させます。

public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
    if (destinationType == typeof(string) || destinationType == typeof(InstanceDescriptor))
        return true;
    else
        return base.CanConvertTo(context, destinationType);
}

public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
    if (value is Shadow)
    {
        Shadow shadow = (Shadow)value;
        if (destinationType == typeof(string))
        {
            ColorConverter colorConverter = new ColorConverter();
            return string.Format("{0}, {1}, {2}",
                                 colorConverter.ConvertToString(shadow.Color),
                                 shadow.Depth, shadow.Direction);
        }
        if (destinationType == typeof(InstanceDescriptor))
        {
            ConstructorInfo ci = typeof(Shadow).GetConstructor(new Type[] 
                    { typeof(Color), typeof(int), typeof(ShadowDirection) });
            if (ci != null)
                return new InstanceDescriptor(ci, new object[]
                    { shadow.Color, shadow.Depth, shadow.Direction });
        }
    }
    return base.ConvertTo(context, culture, value, destinationType);
}
Public Overrides Function CanConvertTo(context As ITypeDescriptorContext, destinationType As Type) As Boolean
    If destinationType = GetType(String) OrElse destinationType = GetType(InstanceDescriptor) Then
        Return True
    Else
        Return MyBase.CanConvertTo(context, destinationType)
    End If
End Function

Public Overrides Function ConvertTo(context As ITypeDescriptorContext, culture As System.Globalization.CultureInfo, value As Object, destinationType As Type) As Object
    If TypeOf value Is Shadow Then
        Dim shadow As Shadow = DirectCast(value, Shadow)
        If destinationType = GetType(String) Then
            Dim colorConverter As New ColorConverter()
            Return String.Format("{0}, {1}, {2}", _
                                 colorConverter.ConvertToString(shadow.Color), _
                                 shadow.Depth, shadow.Direction)
        End If
        If destinationType = GetType(InstanceDescriptor) Then
            Dim ci As ConstructorInfo = GetType(Shadow).GetConstructor(New Type() _
                    {GetType(Color), GetType(Integer), GetType(ShadowDirection)})
            If ci IsNot Nothing Then
                Return New InstanceDescriptor(ci, New Object() _
                        {shadow.Color, shadow.Depth, shadow.Direction})
            End If
        End If
    End If
    Return MyBase.ConvertTo(context, culture, value, destinationType)
End Function

ところが、これがうまく行きません。Shadowの項目を変更しても、InitializeComponentにまったく保存されなくなってしまいました。

これがそのC#のソースファイルVB.NETのソースファイルです。なにかお気づきの方いましたら、掲示板でお知らせください。

«

コメントをどうぞ

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

«