How to create browseable class-properties in .NET / Visual studio

Alright, I got something to work that may satisfy your case.

To get a class to expand in the PropertyGrid, you have to add a TypeConverterAttribute to it, referencing the type of an ExpandableObjectConverter (or something else that derives from it).

[TypeConverter(typeof(ExpandableObjectConverter))]
public class Test
{
    [Browsable(true)]
    public string A { get; set; }
    [Browsable(true)]
    public string B { get; set; }
}

The only problem is that it now displays the type name (the return value of its ToString() method as the value of your class). You can either live with it (which you probably won't want to), change the ToString() return value to something more fitting or use a custom TypeConverter for that case.

I'll show you a quick implementation on how the latter could be done:

internal class TestConverter : ExpandableObjectConverter
{
    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == typeof(string))
            return "";
        return base.ConvertTo(context, culture, value, destinationType);
    }
}

And then you would write this, instead of what I wrote above:

[TypeConverter(typeof(TestConverter))]
public class Test
{
    [Browsable(true)]
    public string A { get; set; }
    [Browsable(true)]
    public string B { get; set; }
}

This just empties the information and prevents the user to enter some other value. You probably want to show something more descriptive which is completely up to you.
It is also possible to get information and parse it into useful values. A good example would be the location, which is an object of type Point visualized with [10,5] when X is 10 and Y is 5. When you enter new values they are parsed and set to the integers that are referenced by the original string.


Because I couldn't find much about the topic, I looked up some references in ReferenceSource, because it had to be done before. In my case, I peeked into ButtonBase and FlatButtonAppearance of WindowsForms to see how Microsoft did it, back in the day.

Hope I could help.


Here is the TypeConverter Class. This allows VS properties to access your object as strings, and convert back to it from strings.

for more about TypeConversion.

class MultiPropConverter : ExpandableObjectConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context,
    Type sourceType)
    {
        if (sourceType == typeof(string)) { return true; }
        return base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture,
        object value)
    {
        if (value is string)
        {
            string[] v = ((string)value).Split(new char[] { ',' });
            if(v.Length == 3) // Check that there are no ',' in your string(s) A.
            {
                return new DropDownProperties(v[0], float.Parse(v[1]), int.Parse(v[2]));
            }
        }
        return base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture,
        object value, Type destinationType)
    {
        if (destinationType == typeof(string)) // What VS properties ask for to display
        {
            DropDownProperties dDP = (DropDownProperties)value;
            return dDP.A + "," + dDP.B.ToString() + "," + dDP.C.ToString();
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }
}

the Multi-Property Class:

[TypeConverter(typeof(MultiPropConverter))]
public class DropDownProperties
{       
    [Description("Description of A")]
    public string A { get; set; } = "Default";      
    [Description("Description of B")]
    public float B { get; set; } = 0f;
    [Description("Description of C")]
    public int C { get; set; } = 1;
}

And then class instantiation:

    [Description("Category Description"), Category("ACategory")]
    public DropDownProperties dropProp { get; set; } = new DropDownProperties() 
    { A = "Hello World", B = "0.1", C = 0};

You do not need the Browsable attribute if you include a category or description for the item.

enter image description here

Cheers!