Edit the display name of enumeration members in a PropertyGrid

19,914

Solution 1

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

Solution 2

The answer I gave here Has a working example of this. Here is the specific code from that example that you want:

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

Solution 3

You can attach a custom TypeConverter implementation to the property whose type is your enumeration and override the GetStandardValuesSupported and GetStandardValues to return a custom list of items to show in the drop-down list in the PropertyGrid. You can then override ConvertFrom/ConvertTo methods to handle converting values to/from your enumeration type.

You may also want to override GetStandardValuesExclusive and have it return "true" so the user can't type anything into the property value.

So, something like this:

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

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

In your implementation of GetStandardValues/ConvertFrom/ConvertTo you could then use Reflection to pull out the DisplayNameAttribute (or DescriptionAttribute, which may be more suited to this task) attributes of the various enum members to show that text instead of hard-coding the list of items to show.

Share:
19,914
Jonathan Henson
Author by

Jonathan Henson

I'm a seasoned software development engineer with broad experience: from web development, to embedded systems, high-level to native development, and everything in-between. I enjoy startups, mentoring other engineers, and playing with new tech.

Updated on June 23, 2022

Comments

  • Jonathan Henson
    Jonathan Henson almost 2 years

    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?

  • Jonathan Henson
    Jonathan Henson over 12 years
    Thanks! that was it. I don't know why, but an hour with Google and I still didn't find that article.
  • lee-m
    lee-m over 12 years
    Nice, I haven't come across EnumConverter in my battles with the PropertyGrid before.
  • Cameron
    Cameron over 10 years
    I like the simplicity of this idea, but unfortunately it didn't work for me (I'm creating Visual Studio options pages, though, not vanilla PropertyGrids).
  • Eugene  Maksimov
    Eugene Maksimov over 9 years
    Hyperlink "Using PropertyGrid in .NET" is not correct now.
  • LarsTech
    LarsTech over 9 years
    @EugeneMaksimov Thanks. I updated the answer and lifted the example code the user posted in case the link goes stale again.
  • LarsTech
    LarsTech almost 8 years
    @FrancescoDS Well, if you are looking for help, I would need more information than that.
  • FrancescoDS
    FrancescoDS almost 8 years
    the enum is like yours, with only two options: "Applica" and "Non Applica" are the descriptions. I've copied the converter in my code and used it with the notation [TypeConverter(typeof(...)] but the descriptions are not shown...what do you also need to know? I've put breakpoints in each method of the converter and it seems that it they are not called...maybe something is missing?
  • LarsTech
    LarsTech almost 8 years
    @FrancescoDS I've just re-tested this code on a PropertyGrid control, and the drop down options were "Applica" and "Non Applica", so there is something you didn't copy correctly.
  • FrancescoDS
    FrancescoDS almost 8 years
    @LarsTech I've copied all code in your answer above...it seems nothing is missing...am I right?
  • LarsTech
    LarsTech almost 8 years
    @FrancescoDS Like I said, I re-tested it and it worked for me. I can't see what you are doing.
  • FrancescoDS
    FrancescoDS almost 7 years
    @LarsTech here is the code gist.github.com/anonymous/05563e32ba52eec834d7225c01cce8ff I already had this issue. What am I doing wrong?
  • LarsTech
    LarsTech almost 7 years
    @FrancescoDS I am getting "Applica" and "Calcola Cerniere Plastiche" as my options in the PropertyGrid. So your code works for me.
  • FrancescoDS
    FrancescoDS almost 7 years
    @LarsTech, i'm using the xceed wpf toolkit for the PropertyGrid: xmlns:xctk="schemas.xceed.com/wpf/xaml/toolkit"<xctk:Propert‌​yGrid x:Name="propertyGrid" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="467" Height="330" IsCategorized="False" ShowTitle="False" ShowSortOptions="False" NameColumnWidth="200"> </xctk:PropertyGrid> maybe something wrong in it?
  • LarsTech
    LarsTech almost 7 years
    @FrancescoDS Unfortunately, that's a different control than the WinForms PropertyGrid I answered on. I have very little WPF experience.
  • uceumern
    uceumern over 3 years
    This did not work for me. I was using Windows Forms Property Grid and it still showed only the plain enum names.