简体   繁体   中英

C# PropertyGrid => How to change visible Properties at Runtime

I have to following problem,

In a map-editor you can place "Joints" (FarseerPhysics) on objects, there are 23 types of joints (in an enum). The joints are all pretty much the same (just 1-2 new properties per jointtype). I want to enable the user to change the joints using a WinForm PropertyGrid. So if the user changes the property "JointType" (the enum), the PropertyGrid needs to hide the old properties and show the new ones, is there a way to achieve that? (All properties of all Joints are saved in ONE class called JointItem, I just need to dynamically show/hide some of them)

There is no simple to use built-in support in PropertyGrid for dynamically altering which properties are visible depending on the value of another property. This doesn't mean it can't be done, just that it takes a bit of work.

As you've already discovered, what controls whether a property is visible or not is the BrowsableAttribute . So basically you need to change this attribute dynamically, and the way to do that is to create your own TypeProvider and TypeDescriptor for your class, that dynamically returns the Browsable(false) or Browsable(true) attribute for the property to be hidden/shown depending on the value of another property in the class. I will not attempt to describe how TypeProvider and TypeDescriptor works here, since it is quite a lengthy subject and there is much information readily available on this subject on the web already.

In addition you need to specify the [RefreshProperties(RefreshProperties.All)] attribute on the property controlling whether another property should be visible or not. This will force the propertygrid to requery the TypeDescriptor for the list of properties whenever its value is changed, giving your TypeDescriptor the chance to return a different set of properties, or different attributes on the properties it returns.

I hope this at least points you in the right direction. Unfortunately it takes a quite bit of work to glue these things together.

Here is a method for changing the Browsable attribute of a property in your JointItem class:

private void ChangeBrowsability(object pThis, string pProperty, bool pBrowsable)
{
    PropertyDescriptor pdDescriptor = TypeDescriptor.GetProperties(pThis.GetType())[pProperty];
    BrowsableAttribute baAttribute = (BrowsableAttribute)pdDescriptor.Attributes[typeof(BrowsableAttribute)];
    FieldInfo fiBrowsable = baAttribute.GetType().GetField("browsable", BindingFlags.NonPublic | BindingFlags.Instance);
    fiBrowsable.SetValue(baAttribute, pBrowsable);
}

Then you could have a big long if then else sequence or the likes:

JointItem jiThis = WhereEverYouGetYourJointItemFrom();
if (jiThis.JointType == eJoinType.Elbow)
{
    ChangeBrowsability(jiThis, "JointAngle", true);
    ChangeBrowsability(jiThis, "MinAngle", true);
    ChangeBrowsability(jiThis, "MaxAngle", true);
    ChangeBrowsability(jiThis, "ScrewType", false);
    //...
}
else ...

Of course you need your dose of "using"s!

using System.ComponentModel;
using System.Reflection;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM