Russell Trahan
Russell Trahan

Reputation: 792

C# like enum desciption attributes in C++/CLI

C# allows the following functionality to display a user-friendly version of enums. The type converter takes the description attribute and uses it to generate a string. Can this be done in C++/CLI? From what I'm seeing, a 'public enum class' cannot have attributes on the enum members. This means I can't define the description attribute content for each enum. How can the friendly names be defined?

[TypeConverter(typeof(EnumDescriptionConverter))]
public enum MyEnum
{
    [Description("Item1")]
    Item1,
    [Description("Item2")]
    Item2, 
}

class EnumDescriptionConverter : EnumConverter
{
    private Type _enumType;
    public EnumDescriptionConverter(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)
    {
        String ReturnString = "";

        if (_enumType.GetCustomAttributes<FlagsAttribute>().Any())
        {
            foreach (var val in EnumExtensions.GetIndividualFlags((Enum)value))
            {
                FieldInfo fi = _enumType.GetField(Enum.GetName(_enumType, val));
                DescriptionAttribute dna = (DescriptionAttribute)Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute));

                if (ReturnString != "")
                    ReturnString += " | ";

                if (dna != null)
                    ReturnString += dna.Description;
                else
                    ReturnString += val.ToString();
            }
        }
        else
        {
            FieldInfo fi = _enumType.GetField(Enum.GetName(_enumType, value));
            DescriptionAttribute dna = (DescriptionAttribute)Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute));

            if (ReturnString != "")
                ReturnString += " | ";

            if (dna != null)
                ReturnString += dna.Description;
            else
                ReturnString += value.ToString();
        }
        return ReturnString;
    }

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

Upvotes: 2

Views: 2315

Answers (2)

Russell Trahan
Russell Trahan

Reputation: 792

After researching this more, I resorted to the following type converter. It simply replaces an underscore in the enum member with a space. It can also handle flags.

ref class EnumDescriptionConverter : public System::ComponentModel::EnumConverter
{
private:
    System::Type^ _enumType;
public:
    EnumDescriptionConverter(System::Type^ type) : System::ComponentModel::EnumConverter(type)
    {
        _enumType = type;
    }

    bool CanConvertTo(System::ComponentModel::ITypeDescriptorContext^ context, System::Type^ destType)override
    {
        return destType == System::String::typeid;
    }

    System::Object^ ConvertTo(System::ComponentModel::ITypeDescriptorContext^ context, System::Globalization::CultureInfo^ culture, System::Object^ value, System::Type^ destType)override
    {
        return value->ToString()->Replace("_", " ");
    }

    bool CanConvertFrom(System::ComponentModel::ITypeDescriptorContext^ context, System::Type^ srcType)override
    {
        return srcType == System::String::typeid;
    }

    System::Object^ ConvertFrom(System::ComponentModel::ITypeDescriptorContext^ context, System::Globalization::CultureInfo^ culture, System::Object^ value)override
    {
        return System::Enum::Parse(_enumType, ((System::String^)value)->Replace(" ", "_")->Replace(",_", ", "));
    }
};

Enums are defined like this:

[System::ComponentModel::TypeConverter(typeof(EnumDescriptionConverter))]
public enum class MyEnum
{
    Item_1, // Appears as 'Item 1' when data bound or in a property grid
    Item_2  // Appears as 'Item 2' when data bound or in a property grid
}

Upvotes: 0

Ben Voigt
Ben Voigt

Reputation: 283614

You've broken the cardinal rule of Stack Overflow questions: You didn't actually include real source code or the exact error message.

This code compiles just fine for me in Visual Studio 2013 in a brand new C++/CLI Console Application project:

using System::ComponentModel::DescriptionAttribute;

public enum class MyEnum
{
    [Description("Item1")]
    Item1,
    [Description("Item2")]
    Item2, 
};

Upvotes: 0

Related Questions