トップ回答者
オブジェクトのプロパティをPropertyGrid上で展開して設定を行いたい

質問
-
オブジェクトのプロパティを、デザイナーのPropertyGrid上で展開して設定を行いたいと思っています。
具体的にはSystem.Drawing.Drawing2D. ColorBlendです。
自作プロパティだとExpandableObjectConverterを利用してプロパティの展開、設定が出来ますが、
ColorBlend(に限らず)は、アクセサを用意しただけではPropertyGrid上からは操作することができません。
public class ExLabel : Label { private ColorBlend _colorBlend = new ColorBlend(); public ColorBlend ColorBlend { get { return _colorBlend; } set { _colorBlend = value; } } }
ColorBlendをラッピングする自作プロパティを用意すれば済むと思いますが、全メソッド・プロパティを
いちいちラッピングするのが果てしなく面倒です。
簡単に、ColorBlendをプロパティとしてPropertyGrid上で操作できるようにする方法はありませんでしょうか?- 編集済み takiru 2013年4月24日 5:03
回答
-
こんな?
[TypeConverter(typeof(ExpandableSubObjectConverter))] public class ExLabel { public ExLabel() { ColorBlend = new System.Drawing.Drawing2D.ColorBlend(); Test = new TestClass(); } public ColorBlend ColorBlend{get;set;} public TestClass Test { get; set; } } public class TestClass { public string Text { get; set; } public DateTime Time { get; set; } } /// <summary> /// クラスに含まれるプロパティで独自のTypeConverterを持っていないプロパティをExpandableObjectConverが指定されているように偽装するConverter /// </summary> class ExpandableSubObjectConverter : ExpandableObjectConverter { public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) { var ps= base.GetProperties(context, value, attributes); List<PropertyDescriptor> list = new List<PropertyDescriptor>(); foreach (PropertyDescriptor pd in ps) { //if (pd.PropertyType != typeof(ColorBlend)) //{ // list.Add(pd); //} //else //{ TypeConverterAttribute tca = null; foreach (Attribute attr in pd.Attributes) { tca = attr as TypeConverterAttribute; if (tca != null) { break; } } if (tca == null) { list.Add(new ExpandPropertyDescriptor(pd)); } else { list.Add(pd); } //} } PropertyDescriptorCollection retval = new PropertyDescriptorCollection(list.ToArray()); return retval; } public override bool GetPropertiesSupported(ITypeDescriptorContext context) { var b= base.GetPropertiesSupported(context); return true; } /// <summary> /// TypeConverterがデフォルトのTyepConverterの場合にExpandableObjectConverterに差し替えるPropertyDescriptor /// </summary> class ExpandPropertyDescriptor : PropertyDescriptor { /// <summary></summary> /// <param name="pd"></param> /// <param name="isExpandSubProperties">さらに下位のプロパティも展開するようにするならtrueにする</param> public ExpandPropertyDescriptor(PropertyDescriptor pd,bool isExpandSubProperties=true) : base(pd) { baseDescriptor = pd; if (isExpandSubProperties) { List<Attribute> list = new List<Attribute>(base.AttributeArray); TypeConverterAttribute tca = new TypeConverterAttribute(typeof(ExpandableSubObjectConverter)); list.Add(tca); base.AttributeArray = list.ToArray(); } } private static ExpandableObjectConverter expandable = new ExpandableObjectConverter(); private PropertyDescriptor baseDescriptor; public override TypeConverter Converter { get { var converter = base.Converter; if (converter.GetType() == typeof(TypeConverter)) { return expandable; } else { return converter; } } } public override bool CanResetValue(object component) { return baseDescriptor.CanResetValue(component); } public override Type ComponentType { get { return baseDescriptor.ComponentType; } } public override object GetValue(object component) { return baseDescriptor.GetValue(component); } public override bool IsReadOnly { get { return baseDescriptor.IsReadOnly; } } public override Type PropertyType { get { return baseDescriptor.PropertyType; } } public override void ResetValue(object component) { baseDescriptor.ResetValue(component); } public override void SetValue(object component, object value) { baseDescriptor.SetValue(component, value); } public override bool ShouldSerializeValue(object component) { return baseDescriptor.ShouldSerializeValue(component); } } }
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 回答としてマーク takiru 2013年4月25日 2:48
すべての返信
-
PropertyGridに出したいというお話しであれば、下記で良いと思います。
public class ExLabel : Label { private ColorBlend _colorBlend = new ColorBlend(); [Browsable(true), Category(分類), DefaultValue(デフォルト値), Description(説明)] public ColorBlend ColorBlend { get { return _colorBlend; } set { _colorBlend = value; } } }
※分類・デフォルト値・説明の部分は適宜設定して下さい。 -
こんな?
[TypeConverter(typeof(ExpandableSubObjectConverter))] public class ExLabel { public ExLabel() { ColorBlend = new System.Drawing.Drawing2D.ColorBlend(); Test = new TestClass(); } public ColorBlend ColorBlend{get;set;} public TestClass Test { get; set; } } public class TestClass { public string Text { get; set; } public DateTime Time { get; set; } } /// <summary> /// クラスに含まれるプロパティで独自のTypeConverterを持っていないプロパティをExpandableObjectConverが指定されているように偽装するConverter /// </summary> class ExpandableSubObjectConverter : ExpandableObjectConverter { public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) { var ps= base.GetProperties(context, value, attributes); List<PropertyDescriptor> list = new List<PropertyDescriptor>(); foreach (PropertyDescriptor pd in ps) { //if (pd.PropertyType != typeof(ColorBlend)) //{ // list.Add(pd); //} //else //{ TypeConverterAttribute tca = null; foreach (Attribute attr in pd.Attributes) { tca = attr as TypeConverterAttribute; if (tca != null) { break; } } if (tca == null) { list.Add(new ExpandPropertyDescriptor(pd)); } else { list.Add(pd); } //} } PropertyDescriptorCollection retval = new PropertyDescriptorCollection(list.ToArray()); return retval; } public override bool GetPropertiesSupported(ITypeDescriptorContext context) { var b= base.GetPropertiesSupported(context); return true; } /// <summary> /// TypeConverterがデフォルトのTyepConverterの場合にExpandableObjectConverterに差し替えるPropertyDescriptor /// </summary> class ExpandPropertyDescriptor : PropertyDescriptor { /// <summary></summary> /// <param name="pd"></param> /// <param name="isExpandSubProperties">さらに下位のプロパティも展開するようにするならtrueにする</param> public ExpandPropertyDescriptor(PropertyDescriptor pd,bool isExpandSubProperties=true) : base(pd) { baseDescriptor = pd; if (isExpandSubProperties) { List<Attribute> list = new List<Attribute>(base.AttributeArray); TypeConverterAttribute tca = new TypeConverterAttribute(typeof(ExpandableSubObjectConverter)); list.Add(tca); base.AttributeArray = list.ToArray(); } } private static ExpandableObjectConverter expandable = new ExpandableObjectConverter(); private PropertyDescriptor baseDescriptor; public override TypeConverter Converter { get { var converter = base.Converter; if (converter.GetType() == typeof(TypeConverter)) { return expandable; } else { return converter; } } } public override bool CanResetValue(object component) { return baseDescriptor.CanResetValue(component); } public override Type ComponentType { get { return baseDescriptor.ComponentType; } } public override object GetValue(object component) { return baseDescriptor.GetValue(component); } public override bool IsReadOnly { get { return baseDescriptor.IsReadOnly; } } public override Type PropertyType { get { return baseDescriptor.PropertyType; } } public override void ResetValue(object component) { baseDescriptor.ResetValue(component); } public override void SetValue(object component, object value) { baseDescriptor.SetValue(component, value); } public override bool ShouldSerializeValue(object component) { return baseDescriptor.ShouldSerializeValue(component); } } }
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 回答としてマーク takiru 2013年4月25日 2:48
-
ご回答ありがとうございます。
おかげさまで実現することができました。
TypeConverterあたりになると理解が及ばず全く思いついたりしないので、大変助かりました。
VS2010だと動きましたが、VS2005に合わせたコードに直して試してみたら、コンパイルエラーにはならないものの、
なぜか上手く展開することができませんでした。バージョン違いがあからさまに影響を受けたシーンを初めて見たので、この機会に、VS2005で作成途中のものを
追記:
VS2010で作りかえようかと思います。
勘違いで、VS2005でも動いてました(^_^;)- 編集済み takiru 2013年4月25日 6:02