ElektroStudios
ElektroStudios

Reputation: 20464

Implementing an Enum Array to String Array TypeConverter in .NET

In C# or VB.NET, under WinForms, I have a property that returns an array of a enum. See an example:

public enum TestEnum: int {
    Name1 = 0,
    Name2 = 1,
    Name3 = 2
} // Note that the enum does not apply for the [Flags] attribute.

public TestEnum[] TestProperty {get; set;} = 
    new[] {TestEnum.Name1, TestEnum.Name2, TestEnum.Name3};

By default, a PropertyGrid will show the values as int[], like: {0, 1, 2} instead of the enumeration value names, like: {"Name1", "Name2", "Name2"}, which is the visual representation that I would like to acchieve...

So, I would like to design a TypeConverter that could be able to return a string array with the value names, and apply it like this:

[TypeConverter(typeof(EnumArrayToStringArrayTypeConverter))]
public TestEnum[] TestProperty {get; set;} = 
    new[] {TestEnum.Name1, TestEnum.Name2, TestEnum.Name3};

In other words, If my property is represented like this in a PropertyGrid:

enter image description here

I would like to have this:

enter image description here


The biggest problem I'm facing is trying to retrieve the type of the enum from the custom type-converter class, to be able get the value names of that enum. I only can get the primitive data type of the array (like: int[], uint16[], etc)...

public class EnumArrayToStringArrayTypeConverter : TypeConverter {
    // ...

    public override object ConvertTo(ITypeDescriptorContext context, 
                                     CultureInfo culture, 
                                     object value, 
                                     Type destinationType) {

        if (destinationType == null) {
            throw new ArgumentNullException(nameof(destinationType));
        }

        try {
            // This will return the array-type for the 
            // primitive data type of the declared enum, 
            // such as int[], uint16[], etc.
            Type t = value.GetType(); 

            // I'm stuck at this point. 
            // ...

        } catch (Exception ex) {

        }

        return null;
    }

    // ...
}

Please take into account that I'm asking for a reusable solution that can work for any kind of enum. And, my enum in this example does not have the [Flags] attribute applied, but a solution should care about enums having it, so, If a enum item of the enum array is a enum that has various flags, those flags (the value names) should be concatenated for example using string.join().

Upvotes: 3

Views: 1041

Answers (2)

ElektroStudios
ElektroStudios

Reputation: 20464

As mentioned by @NineBerry in his answer, the PropertyGrid does already show the names for the enum values. However, I discovered that exists a strange circumstance on wich it will not do it...

Since my original source-code is written in VB.NET, I'll put VB.NET sample codes to reproduce the issue.

The thing is that I was getting a value from a instance of a WMI class (specifically: Win32_DiskDrive.Capabilities), which returns an object that needs to be casted to a uint16 array. Then, I was casting that resulting uint16 array to my type of enum. To simplify things, I will not show WMI code, but an object that represents what I was getting from WMI...

Dim wmiValue As Object = {1US, 2US, 3US}
Dim castedValue As UShort() = DirectCast(wmiValue, UShort())
TestProperty = DirectCast(castedValue, TestEnum())

So, when doing that type-casting, and thanks to @NineBerry answer, I discovered that for some reason the default type converter of TestProperty goes wrong and the PropertyGrid shows uint16 values instead of the enum value-names.

( Note that using DirectCast() or CType() in VB.NET, it didn't changed the PropertyGrid behavior. )

To fix the error, I ended using Array.ConvertAll(), and then the PropertyGrid properly shows the value-names...

Dim wmiValue As Object = {1US, 2US, 3US}
Dim castedValue As UShort() = DirectCast(wmiValue, UShort())
TestProperty = Array.ConvertAll(castedValue,
                                Function(value As UShort)
                                    Return DirectCast(value, TestEnum)
                                End Function)

Upvotes: 1

NineBerry
NineBerry

Reputation: 28499

The PropertyGrid does already show the names for the enum values. It can even handle [Flags] correctly. See the sample below using a form with a default PropertyGrid and a default button and nothing else.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    [Flags]
    public enum TestEnum : int
    {
        Name1 = 0,
        Name2 = 1,
        Name3 = 2
    } 

    public class TestObject
    {
        public string Name { get; set; } = "Hello World";
        public TestEnum[] TestProperty { get; set; } =
            new[] { TestEnum.Name1, TestEnum.Name2 | TestEnum.Name3, TestEnum.Name3 };
    }

    private void button1_Click(object sender, EventArgs e)
    {
        TestObject o = new TestObject();
        propertyGrid1.SelectedObject = o;
    }
}

enter image description here enter image description here

Please supply some example code that can reproduce that the enum names are not shown in the PropertyGrid. You must be doing something wrong in the first place.

Upvotes: 1

Related Questions