1

我在我的应用程序中使用 PropertyGrid。我需要在运行时根据自定义数据标准更改某些属性的可见性和只读性。

虽然我没有找到简单的东西并准备好,但我找到了一种解决方法,方法是在运行时更改ReadOnlyAttributeandBrowsableAttribute 属性,如下所示:

protected void SetBrowsable(string propertyName, bool value)
{
    PropertyDescriptor property = TypeDescriptor.GetProperties(GetType())[propertyName];
    BrowsableAttribute att = (BrowsableAttribute)property.Attributes[typeof(BrowsableAttribute)];
    FieldInfo cat = att.GetType().GetField("browsable", BindingFlags.NonPublic | BindingFlags.Instance);

    if (property.Attributes.Cast<Attribute>().Any(p => p.GetType() == typeof(BrowsableAttribute)))
        cat.SetValue(att, value);
}

protected void SetReadOnly(string propertyName, bool value)
{
    PropertyDescriptor property = TypeDescriptor.GetProperties(GetType())[propertyName];
    ReadOnlyAttribute att = (ReadOnlyAttribute)property.Attributes[typeof(ReadOnlyAttribute)];
    FieldInfo cat = att.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);

    if (property.Attributes.Cast<Attribute>().Any(p => p.GetType() == typeof(ReadOnlyAttribute)))
        cat.SetValue(att, value);
}

现在,我的问题是我应该在哪里调用这些方法?有什么我可以处理的事件object来调用这些方法吗?也许通过实现一个接口。

4

1 回答 1

1

调用 property-get 时不会触发内置事件,除非您编写一个。

当然,如果您编写自定义描述符(PropertyDescriptor,通常作为装饰器链接到反射描述符),您可以仅通过描述符拦截访问(数据绑定等),并做任何您想做的事情 - 但对于任意类型(包括那些你没写)。

在运行时通过反射设置属性值......不是很好。这主要是由于 TypeDescriptor 缓存的意外。如果你打算这样做,TypeDescriptor.AddAttributes (或类似的)是更可取的。但是,通过实现自定义模型,您尝试做的事情会更合适。根据您显示的位置,这可以通过一个或以下方式完成:

  • 添加自定义 TypeConverter,覆盖 GetProperties,并在运行时根据数据提供自定义描述符 - 主要适用于 PropertyGrid
  • 在对象中实现 ICustomTypeDescriptor,实现 GetProperties,并在运行时根据数据提供自定义描述符 - 适用于大多数控件
  • 添加自定义 TypeDescriptionProvider 并与类型 (TypeDescriptor.AddProvider) 关联,提供与上述行为类似的 ICustomTypeDescriptor;这将对象与描述符 voodoo 分开

所有这些都很棘手!最简单的是 TypeConverter 选项,因为您提到了 PropertGrid,所以效果很好。从 ExpandableObjectConverter 继承,并覆盖 GetProperties,根据需要进行过滤,并根据需要为只读描述符提供自定义描述符。然后将 TypeConverterAttribute 附加到您的类型,指定您的自定义转换器类型。

重点:.NET 的这个分支非常复杂、晦涩难懂,而且使用量正在减少。但它有效。

于 2012-04-29T13:09:18.060 回答