在我的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#,因此超出了我在这里提供的合理范围。