2014-10-01 136 views
1

我正在开发一组自定义控件。我有多个属性,我想组合在一起。自定义控件的自定义属性

我知道我可以做这样的事情:

[Category("HoverStyle"), Description("Specifies if the label will bold when the mouse is hovering.")] 
public bool HoverBold { get; set; } 

[Category("HoverStyle"), Description("Specifies if the label will italicize when the mouse is hovering.")] 
public bool HoverItalicize { get; set; } 

[Category("HoverStyle"), Description("Specifies if the label will underline when the mouse is hovering.")] 
public bool HoverUnderline { get; set; } 

但是当你组织属性网格中的字母顺序,他们将不会出现在一组。我希望每个属性都显示为结构的属性,就像x和y坐标出现在控件的Location属性下一样。

我试图创建一个struct像这样:

public struct HoverStyle 
{ 
    public bool Bold { get; set; } 
    public bool Italicize { get; set; } 
    public bool Underline { get; set; } 
} 

但这并不表现我打算的方式。谢谢你的帮助!

+1

[自定义属性与Visual Studio的属性窗格中的子属性]的可能重复(http://stackoverflow.com/questions/25957685/custom-property-with-sub-properties-in-visual-studios-properties-窗格) – Dmitry 2014-10-01 22:10:50

回答

1

虽然这不是确切情况的答案,但同样的解决方案也适用。在这个解决方案中,我展示了我如何完成上述描述,但是使用了一个为我绘制的控件定义TopLeft,TopRight,BottomLeft和BottomRight半径的结构。我创建了我自己的结构和TypeConverter。

[Serializable] 
[TypeConverter(typeof(CornerRadiiConverter))] 
public struct CornerRadii 
{ 
    private bool all; 
    private int topLeft, topRight, bottomLeft, bottomRight; 

    public readonly static CornerRadii Empty; 

    [RefreshProperties(RefreshProperties.All)] 
    public int All 
    { 
     get 
     { 
      if (!this.all) 
       return -1; 
      return this.topLeft; 
     } 
     set 
     { 
      if (!this.all || this.topLeft != value) 
      { 
       this.all = true; 
       this.topLeft = value; 
       this.topRight = value; 
       this.bottomLeft = value; 
       this.bottomRight = value; 
      } 
     } 
    } 

    [RefreshProperties(RefreshProperties.All)] 
    public int TopLeft 
    { 
     get 
     { 
      return this.topLeft; 
     } 
     set 
     { 
      if (this.all || this.topLeft != value) 
      { 
       this.all = false; 
       this.topLeft = value; 
      } 
     } 
    } 

    [RefreshProperties(RefreshProperties.All)] 
    public int TopRight 
    { 
     get 
     { 
      if (this.all) 
       return this.topLeft; 
      return this.topRight; 
     } 
     set 
     { 
      if (this.all || this.topRight != value) 
      { 
       this.all = false; 
       this.topRight = value; 
      } 
     } 
    } 

    [RefreshProperties(RefreshProperties.All)] 
    public int BottomLeft 
    { 
     get 
     { 
      if (this.all) 
       return this.topLeft; 
      return this.bottomLeft; 
     } 
     set 
     { 
      if (this.all || this.bottomLeft != value) 
      { 
       this.all = false; 
       this.bottomLeft = value; 
      } 
     } 
    } 

    [RefreshProperties(RefreshProperties.All)] 
    public int BottomRight 
    { 
     get 
     { 
      if (this.all) 
       return this.topLeft; 
      return this.bottomRight; 
     } 
     set 
     { 
      if (this.all || this.bottomRight != value) 
      { 
       this.all = false; 
       this.bottomRight = value; 
      } 
     } 
    } 

    static CornerRadii() 
    { 
     CornerRadii.Empty = new CornerRadii(0); 
    } 

    public CornerRadii(int all) 
    { 
     this.all = true; 
     this.topLeft = all; 
     this.topRight = all; 
     this.bottomLeft = all; 
     this.bottomRight = all; 
    } 

    public CornerRadii(int topLeft, int topRight, int bottomLeft, int bottomRight) 
    { 
     this.topLeft = topLeft; 
     this.topRight = topRight; 
     this.bottomLeft = bottomLeft; 
     this.bottomRight = bottomRight; 
     this.all = (this.topLeft != this.topRight || this.topLeft != this.bottomRight ? false : this.topLeft == this.bottomRight); 
    } 

    internal bool ShouldSerializeAll() 
    { 
     return this.all; 
    } 
} 

public class CornerRadiiConverter : TypeConverter 
{ 
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] 
    public CornerRadiiConverter() 
    { 
    } 

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
    { 
     if (sourceType == typeof(string)) 
     { 
      return true; 
     } 
     return base.CanConvertFrom(context, sourceType); 
    } 

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

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 
    { 
     string str = value as string; 
     if (str == null) 
      return base.ConvertFrom(context, culture, value); 
     str = str.Trim(); 
     if (str.Length == 0) 
      return null; 
     if (culture == null) 
      culture = CultureInfo.CurrentCulture; 
     char delimiter = culture.TextInfo.ListSeparator[0]; 
     string[] strArray = str.Split(new char[] { delimiter }); 
     int[] numArray = new int[strArray.Length]; 
     TypeConverter converter = TypeDescriptor.GetConverter(typeof(int)); 
     for (int i = 0; i < numArray.Length; i++) 
      numArray[i] = (int)converter.ConvertFromString(context, culture, strArray[i]); 
     if (numArray.Length != 4) 
     { 
      object[] objArray = new object[] { "value", str, "topLeft, topRight, bottomLeft, bottomRight" }; 
      throw new ArgumentException(); 
     } 
     return new CornerRadii(numArray[0], numArray[1], numArray[2], numArray[3]); 
    } 

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 
    { 
     if (destinationType == null) 
      throw new ArgumentNullException("destinationType"); 
     if (value is CornerRadii) 
      if (destinationType == typeof(string)) 
      { 
       CornerRadii cornerRadii = (CornerRadii)value; 
       if (culture == null) 
        culture = CultureInfo.CurrentCulture; 
       string str = string.Concat(culture.TextInfo.ListSeparator, " "); 
       TypeConverter converter = TypeDescriptor.GetConverter(typeof(int)); 
       string[] strArrays = new string[4]; 
       strArrays[0] = converter.ConvertToString(context, culture, cornerRadii.TopLeft); 
       strArrays[1] = converter.ConvertToString(context, culture, cornerRadii.TopRight); 
       strArrays[2] = converter.ConvertToString(context, culture, cornerRadii.BottomLeft); 
       strArrays[3] = converter.ConvertToString(context, culture, cornerRadii.BottomRight); 
       return string.Join(str, strArrays); 
      } 
      if (destinationType == typeof(InstanceDescriptor)) 
      { 
       CornerRadii cornerRadii1 = (CornerRadii)value; 
       if (cornerRadii1.ShouldSerializeAll()) 
       { 
        ConstructorInfo constructor = typeof(CornerRadii).GetConstructor(new Type[] { typeof(int) }); 
        object[] all = new object[] { cornerRadii1.All }; 
        return new InstanceDescriptor(constructor, all); 
       } 
       Type type = typeof(CornerRadii); 
       Type[] typeArray = new Type[] { typeof(int), typeof(int), typeof(int), typeof(int) }; 
       ConstructorInfo constructorInfo = type.GetConstructor(typeArray); 
       object[] left = new object[] { cornerRadii1.TopLeft, cornerRadii1.TopRight, cornerRadii1.BottomLeft, cornerRadii1.BottomRight }; 
       return new InstanceDescriptor(constructorInfo, left); 
      } 
     return base.ConvertTo(context, culture, value, destinationType); 
    } 

    public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues) 
    { 
     if (context == null) 
      throw new ArgumentNullException("context"); 
     if (propertyValues == null) 
      throw new ArgumentNullException("propertyValues"); 
     CornerRadii value = (CornerRadii)context.PropertyDescriptor.GetValue(context.Instance); 
     int item = (int)propertyValues["All"]; 
     if (value.All != item) 
      return new CornerRadii(item); 
     return new CornerRadii((int)propertyValues["TopLeft"], (int)propertyValues["TopRight"], (int)propertyValues["BottomLeft"], (int)propertyValues["BottomRight"]); 
    } 

    public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) 
    { 
     return true; 
    } 

    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) 
    { 
     PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(CornerRadii), attributes); 
     string[] strArrays = new string[] { "All", "TopLeft", "TopRight", "BottomLeft", "BottomRight" }; 
     return properties.Sort(strArrays); 
    } 

    public override bool GetPropertiesSupported(ITypeDescriptorContext context) 
    { 
     return true; 
    } 
} 

我会说,我真的不希望采取的这么多的信贷,因为这种结构和类型转换器是几乎相同的填充结构和类型转换器,只是一些调整。你可能会认为角落的半径不能小于0,你说得对!这是我在自定义控件中设置属性时检查的内容,虽然在写这篇文章时,我想我可以将它放入结构中,而不是......我们会看到。

0

您需要指定它的行为如预期的那样。无论如何,请尝试:

[TypeConverter(typeof(ExpandableObjectConverter))] 
public struct HoverStyle 
{ 
    public bool Bold { get; set; } 
    public bool Italicize { get; set; } 
    public bool Underline { get; set; } 
}