Search code examples
c#winformsenumspropertygrid

How to display an enum with duplicate values in a .NET PropertyGrid?


I have an enum that contains duplicate values. For example:

public enum DataVals : byte 
{
    C1_Route1to2 = 1,
    C4_Route3to5 = 1,
    C6_Route1to2 = 2,
    C7_Route3to5 = 2
}

The values C# are just internal values within my application. Depending on which route is selected by the user, route is another property in the class, a 1 could mean use C1 or C4. The problem is I am using a PropertyGrid in my Winform and this property displays the duplicate values as having the same name. So C1_Route1to2 shows up twice instead of both C1_Route1to2 and C4_Route3to5.

How do I tell the PropertyGrid to display each unique name, rather than duplicating the values?


Solution

  • Although I agree with Gabriel, you could achieve what you need using the TypeConverter as I mentioned before. You might need to change the editor to allow selecting more than one enum if it has the FlagsAttribute...

    Place the attribute:

    [TypeConverter(typeof(ComplexEnumConverter ))]
    public enum DataVals : byte 
    {
        C1_Route1to2 = 1,
        C4_Route3to5 = 1,
        C6_Route1to2 = 2,
        C7_Route3to5 = 2
    }
    

    And here is the converter:

    public class ComplexEnumConverter : EnumConverter
        {
            public bool IsFlagged { get; }
    
            public string[] EnumValues { get; }
    
            public ComplexEnumConverter(Type type)
                : base(type)
            {
                IsFlagged = TypeDescriptor.GetAttributes(type).OfType<FlagsAttribute>().Any();
                EnumValues = Enum.GetNames(type);
            }
    
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
            {
                return sourceType == typeof(string);
            }
    
            public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
            {
                return destinationType == typeof(string);
            }
    
            public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
            {
                var str = value as string;
                if (!string.IsNullOrWhiteSpace(str))
                {
                    var values = str.Split(',').Select(s => s.Trim());
                    var enumValue = Enum.Parse(EnumType, values.First());
                    if (IsFlagged)
                    {
                        var temp = (int)enumValue;
                        foreach (var item in values.Skip(1))
                        {
                            temp |= (int)Enum.Parse(EnumType, item);
                        }
    
                        enumValue = temp;
                    }
    
                    return enumValue;
                }
    
                return base.ConvertFrom(context, culture, value);
            }
    
            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
            {
                var type = value?.GetType();
                if (type == EnumType)
                {
                    var list = new List<string>();
                    int k = (int)value;
                    foreach (var item in Enum.GetNames(type))
                    {
                        var current = (int)Enum.Parse(type, item);
                        if ((k & current) == current)
                        {
                            list.Add(item);
                        }
                    }
    
                    return list.Aggregate((c, n) => $"{c}, {n}");
                }
    
                return base.ConvertTo(context, culture, value, destinationType);
            }
    
            public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
            {
                return context.PropertyDescriptor.PropertyType.IsEnum;
            }
    
            public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
            {
                return context.PropertyDescriptor.PropertyType.IsEnum;
            }
    
            public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
            {
                return new StandardValuesCollection(EnumValues);
            }
        }