Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

How I can make something like this in VS properties Window (collapsible multi properties):

enter image description here

I tried such code:

   Test z = new Test();

    [ Browsable(true)]
    public Test _TEST_ {
        get { return z; }
        set { z = value; }
    }

Where "Test" class is:

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

But this gives me only grayed-out name of class

enter image description here

like image 534
Maciej Avatar asked Mar 02 '20 20:03

Maciej


People also ask

What is browsable attribute in C#?

The Browsable attribute specifies whether or not the Properties window will display a corresponding property at design time.

What are class properties in VB net?

A property is a value or characteristic held by a Visual Basic object, such as Caption or Fore Color. Properties can be set at design time by using the Properties window or at run time by using statements in the program code. Object is the name of the object you're customizing.


Video Answer


2 Answers

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.

like image 93
Max Play Avatar answered Oct 11 '22 16:10

Max Play


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!

like image 36
Daniel Lord Avatar answered Oct 11 '22 15:10

Daniel Lord