c# PropertyGrid =>如何在运行时更改可见属性

本文关键字:属性 运行时 PropertyGrid | 更新日期: 2023-09-27 18:08:19

我有以下问题,

在一个地图编辑器中,你可以在物体上放置"关节"(FarseerPhysics),有23种类型的关节(在enum中)。关节几乎都是一样的(每个关节类型只有1-2个新属性)。我想让用户使用WinForm PropertyGrid来改变关节。因此,如果用户更改属性"JointType"(枚举),PropertyGrid需要隐藏旧属性并显示新属性,有办法实现这一点吗?(所有关节的所有属性都保存在一个类称为JointItem,我只需要动态显示/隐藏其中的一些)

c# PropertyGrid =>如何在运行时更改可见属性

PropertyGrid中使用内置支持并不容易根据另一个属性的值动态更改哪些属性是可见的。这并不意味着它不可能完成,只是需要一些工作。

正如您已经发现的,控制属性是否可见的是BrowsableAttribute。所以基本上你需要动态地改变这个属性,这样做的方法是为你的类创建你自己的TypeProviderTypeDescriptor,根据类中另一个属性的值动态地返回属性的Browsable(false)Browsable(true)属性来隐藏/显示。我不会试图在这里描述TypeProviderTypeDescriptor是如何工作的,因为它是一个相当长的主题,并且在网上已经有很多关于这个主题的信息。

此外,您需要在属性上指定[RefreshProperties(RefreshProperties.All)]属性,以控制另一个属性是否应该可见。这将迫使propertygrid在其值更改时重新查询TypeDescriptor的属性列表,从而使TypeDescriptor有机会返回一组不同的属性,或者在它返回的属性上使用不同的属性。

我希望这至少能给你指明正确的方向。不幸的是,把这些东西粘合在一起需要做很多工作。

下面是一个改变JointItem类中属性的Browsable属性的方法:

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

那么你可以有一个很长的if Then else序列或者类似的:

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 ...

当然你需要你的"使用"的剂量!

using System.ComponentModel;
using System.Reflection;