I have a PropertyGrid in my winforms application that displays the some of the selected object's properties. I want that a certain property will be sometimes displayed and somtimes won't, by my choice, (lets assume the the browsability changes every time a specific button is pressed at runtime). Setting-up the browsability before runtime is pretty easy, using the BrowsableAttribute, from what I understand that attributes are set at design time hence I need another solution. In many places I found this piece of code:
public static void ChangeBrowsability(SomeObject obj, string propertyName, bool isBrowsable)
{//usage: supposed to change browsability at runtime
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(obj)[propertyName];
BrowsableAttribute attrib = (BrowsableAttribute)descriptor.Attributes[typeof(BrowsableAttribute)];
FieldInfo browsableField = attrib.GetType().GetField("browsable", BindingFlags.NonPublic | BindingFlags.Instance);
browsableField.SetValue(attrib, isBrowsable);
}
The first problem is the browsableField
is always null for some reason, and I would like to know why.
Also an alternative solution to this code may be welcomed.
CodePudding user response:
You can't change the reality of how attributes are defined - they are baked into the IL; however, you can lie and cheat. The winforms PropertyGrid
doesn't go directly to reflection - it uses an indirect route via TypeDescriptor
, and TypeDescriptor
defaults to using reflection. However, you can implement your own descriptor implementations that change everything, in particular (for this case): PropertyDescriptor.IsBrowsable
. That's the good news.
The bad news that this is hard. Like; really hard; you'd have to really, really care about this feature to use it. It involves:
- capturing the outgoing reflection-based
ICustomTypeDescriptor
, so you can use it as a foundation - implementing your own
ICustomTypeDescriptor
that exposes the properties as a "decorator" - registering a
TypeDescriptionProvider
that exposes your own type descriptor - capturing the outgoing reflection-based
PropertyDescriptorCollection
so you can use them as a foundation - implementing your own decorators of the
PropertyDescriptor
s, forwarding most of the APIs, except forIsBrowsable
where you would add your own logic
Doable, but: very complex and convoluted, and honestly: using APIs that are largely out of fashion and which haven't seen love in a decade. A worked example could easily run into the hundreds of lines of C#, so is beyond what I can reasonably supply here.