Search code examples
c#.netwinformspropertygrid

Edit the display name of enumeration members in a PropertyGrid


I have a property grid that I am using for users to be able to configure objects for any plugin that is written to be used in my application. I would like to be able to tell developers writing plugins to use the ComponentModel Attributes for their members like so:

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

This works great. Now I would like for the members of an enumeration to be able to be edited as well. i.e.

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

So that they are displayed in the PropertyGrid's list like so:

 DCIF
 CIF
 QCIF
 CIF4
 CIF2

Along with any Descriptions and Display names they may have with them.

It seems that I can only do this with properties, events, and methods. Does anyone know how I can do this for an enumeration?


Solution

  • You will have to make an EnumConverter class and decorate your property with a TypeConverter attribute in order to do this.

    See this Using PropertyGrid in .NET, it's a fun example:

    Imagine that you want more than two items in list. The boolean type is not enough; you need to set Description attributes with a name for every element in enum.

    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
    }
    

    In another class you need to utilize the type 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);
      }
    }
    

    Third, you need set the attribute TypeConverter for displaying the property.

    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; }
      }
    }