在运行时更改属性的可浏览性



在我的winforms应用程序中有一个PropertyGrid,它显示了所选对象的一些属性。我希望某个属性有时会显示,有时不会,由我的选择,(让我们假设每次在运行时按下特定按钮时可浏览性都会发生变化)。在运行之前设置可浏览性是很容易的,使用BrowsableAttribute,从我的理解,属性是在设计时设置的,因此我需要另一个解决方案。在很多地方我都发现了这段代码:

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);
}
第一个问题是browsableField总是出于某种原因,我想知道为什么。此外,也欢迎此代码的替代解决方案。

你不能改变属性定义的现实-它们被嵌入到IL中;然而,你可以撒谎和欺骗。winformsPropertyGrid不直接进行反射-它通过TypeDescriptor使用间接路由,而TypeDescriptor默认使用反射。但是,您可以实现自己的描述符实现,使改变的所有内容,特别是(对于这种情况):PropertyDescriptor.IsBrowsable。这是好消息。

坏消息是这是。像;真的硬;你必须真的,真的关心这个特性才能使用它。它包括:

  • 捕获基于输出反射的ICustomTypeDescriptor,因此您可以将其用作基础
  • 实现自己的ICustomTypeDescriptor,将属性公开为"装饰器">
  • 注册一个TypeDescriptionProvider来公开你自己的类型描述符
  • 捕获基于输出反射的PropertyDescriptorCollection,以便您可以将它们用作基础
  • 实现自己的PropertyDescriptor装饰器,转发大多数api,除了IsBrowsable,你可以添加自己的逻辑

可行,但是:非常复杂和令人费解,老实说:使用的api在很大程度上已经过时了,十年来都没有人喜欢。一个有效的示例可以很容易地涉及数百行c#,因此超出了我在这里提供的合理范围。