2011-09-14 36 views
12

我有我使用对于用户而言,能够为被写在我的应用程序中使用任何插件配置对象的属性网格。我希望能够告诉开发人员编写的插件使用ComponentModel属性为他们的成员,像这样:编辑枚举成员的显示名称中的PropertyGrid

[CategoryAttribute("On Screen Display Settings"), 
DescriptionAttribute("Whether or not to show the session timer."), 
DisplayName("Show Session Timer")] 
public bool ShowTimer 
{ 
    get; 
    set; 
} 

这个伟大的工程。现在我想让枚举的成员也可以编辑。即

public enum Resolution_ : byte 
{ 
    DCIF, 
    CIF, 
    QCIF, 
    [DisplayName("4CIF")] 
    CIF4, 
    [DisplayName("2CIF")] 
    CIF2 
} 

,使它们显示在PropertyGrid中的列表,像这样:

DCIF 
CIF 
QCIF 
CIF4 
CIF2 

随着他们可以与他们有任何说明和显示名称。

看来我只能属性,事件和方法做到这一点。有谁知道我可以怎样做这个枚举?

回答

14

您必须制作一个EnumConverter课程并用TypeConverter属性修饰您的房产才能实现此目的。

看到这个Using PropertyGrid in .NET,这是一个有趣的例子:

试想一下,你想在名单两件以上商品。布尔类型是不够的;您需要为枚举中的每个元素使用名称来设置Description属性。

enum DrinkDoses { 
    [Description("Half of litre")] 
    litre, 
    [Description("One litre")] 
    oneLitre, 
    [Description("Two litres")] 
    twoLitre, 
    [Description("Three litres")] 
    threeLitres, 
    [Description("Four litres")] 
    fourLitres, 
    [Description("Death dose, five litres")] 
    fiveLitres 
} 

在你需要利用类型EnumConverter另一个类。

class DrinkDosesConverter : EnumConverter { 
    private Type enumType; 

    public DrinkDosesConverter(Type type) : base(type) { 
    enumType = type; 
    } 

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destType) { 
    return destType == typeof(string); 
    } 

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, 
            object value, Type destType) { 
    FieldInfo fi = enumType.GetField(Enum.GetName(enumType, value)); 
    DescriptionAttribute dna = (DescriptionAttribute)Attribute.GetCustomAttribute(fi, 
           typeof(DescriptionAttribute)); 
    if (dna != null) 
     return dna.Description; 
    else 
     return value.ToString(); 
    } 

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type srcType) { 
    return srcType == typeof(string); 
    } 

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, 
            object value) { 
    foreach (FieldInfo fi in enumType.GetFields()) { 
     DescriptionAttribute dna = (DescriptionAttribute)Attribute.GetCustomAttribute(fi, 
            typeof(DescriptionAttribute)); 
     if ((dna != null) && ((string)value == dna.Description)) 
     return Enum.Parse(enumType, fi.Name); 
    } 
    return Enum.Parse(enumType, (string)value); 
    } 
} 

第三,你需要设置属性的TypeConverter显示属性。

class DrinkerDoses { 
    DrinkDoses doses; 
    [DisplayName("Doses")] 
    [Description("Drinker doses")] 
    [Category("Alcoholics drinking")] 
    [TypeConverter(typeof(DrinkDosesConverter))] 
    public DrinkDoses Doses { 
    get { return doses; } 
    set { doses = value; } 
    } 
    int dataInt; 
    public int DataInt { 
    get { return dataInt; } 
    set { dataInt = value; } 
    } 
} 
+0

谢谢!就是这样。我不知道为什么,但Google和我一个小时仍然没有找到那篇文章。 –

+0

不错,我之前没有遇到过与PropertyGrid进行过战斗的EnumConverter。 –

+0

“在.NET中使用PropertyGrid”的超链接现在不正确。 –

3

您可以将自定义的TypeConverter实施,其类型为你列举的财产和重写GetStandardValuesSupportedGetStandardValues返回项的自定义列表中PropertyGrid中的下拉列表中显示。然后,您可以覆盖ConvertFrom /的ConvertTo方法来处理从您的枚举类型的值转换成/。

您可能还需要重写GetStandardValuesExclusive,并有使用户可以不输入任何东西到属性值就返回“真”。

所以,这样的事情:

public class MyTypeConverter : TypeConverter 
{ 
    //Override GetStandardValuesExclusive, 
    //GetStandardValues and GetStandardValuesSupported 
} 

public class SomeClass 
{ 
    [TypeConverter(typeof(MyTypeConverter))] 
    public Resolution SomePropertry 
    { 
     ... 
    } 
} 

在您的实现GetStandardValues/ConvertFrom /的ConvertTo的,那么你可以使用反射来拉出DisplayNameAttribute(或DescriptionAttribute,这可能是更适合这个任务)属性各种枚举成员的显示的硬编码项显示的列表中文字。

4

我给here的回答这个工作的例子。下面是从这个例子,你想要的特定代码:

/// <summary> 
/// This attribute is used to represent a string value 
/// for a value in an enum. 
/// </summary> 
public class StringValueAttribute : Attribute { 

    #region Properties 

    /// <summary> 
    /// Holds the stringvalue for a value in an enum. 
    /// </summary> 
    public string StringValue { get; protected set; } 

    #endregion 

    #region Constructor 

    /// <summary> 
    /// Constructor used to init a StringValue Attribute 
    /// </summary> 
    /// <param name="value"></param> 
    public StringValueAttribute(string value) { 
     this.StringValue = value; 
    } 

    #endregion 

} 

public static class MyExtension 
{ 
    public static string GetStringValue(this Enum value) 
    { 
     // Get the type 
     Type type = value.GetType(); 

     // Get fieldinfo for this type 
     FieldInfo fieldInfo = type.GetField(value.ToString()); 

     // Get the stringvalue attributes 
     StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
      typeof(StringValueAttribute), false) as StringValueAttribute[]; 

     // Return the first if there was a match. 
     return attribs.Length > 0 ? attribs[0].StringValue : null; 
    } 

    public static String[] GetEnumNames(Type t) 
    { 
     Array enumValueArray= Enum.GetValues(t); 

     string[] enumStrings = new String[enumValueArray.Length]; 
     for(int i = 0; i< enumValueArray.Length; ++i) 
     { 
      enumStrings[i] = GetStringValue((test)enumValueArray.GetValue(i)); 
     } 

     return enumStrings; 
    } 
} 

enum test 
{ 
    [StringValue("test ONE")] 
    test1, 
    [StringValue("test TWO")] 
    test2 
} 
1

这也似乎工作:

[AttributeUsage(AttributeTargets.Field)] 
public class EnumDisplayNameAttribute : System.ComponentModel.DisplayNameAttribute 
{ 
    public EnumDisplayNameAttribute(string data) : base(data) { } 
} 

public enum Resolution_ : byte 
{ 
    DCIF, 
    CIF, 
    QCIF, 
    [EnumDisplayName("4CIF")] 
    CIF4, 
    [EnumDisplayName("2CIF")] 
    CIF2 
} 

组件寻找通过反射一个显示名称属性会发现一个,并且尽我所能告诉这个作品。这有可能是一个坏主意吗?

+0

我喜欢这个想法的简单性,但不幸的是它并没有为我工作(我创建Visual Studio选项页面,但不是香草PropertyGrids)。 – Cameron