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のソースファイルです。なにかお気づきの方いましたら、掲示板でお知らせください。
2014年1月12日