PropertyGrid对象级别的readonly属性

时间:2012-05-07 12:17:45

标签: c# .net propertygrid propertydescriptor readonly-attribute

我想在PropertyGrid中显示一个班级的多个实例。该课程如下:

public class Parameter
{
    [Description("the name")]
    public string Name { get; set; }

    [Description("the value"), ReadOnly(true)]
    public string Value { get; set; }

    [Description("the description")]
    public string Description { get; set; }
}

我在TreeView中有很多该类的实例。当我在TreeView中选择其中一个时,属性会按预期显示在PropertyGrid中。到目前为止一切顺利,但我想以下列方式自定义此行为:

对于每个单个实例,我希望能够阻止用户修改特定属性。通过在我的班级中设置ReadOnly(true)(如上例所示),所有Value属性都将在班级上停用。

经过一番研究后,我发现以下解决方案让我有机会在运行时启用/禁用特定属性:

PropertyDescriptor descriptor = TypeDescriptor.GetProperties(this)["Value"];

ReadOnlyAttribute attr = 
        (ReadOnlyAttribute)descriptor.Attributes[typeof(ReadOnlyAttribute)];

FieldInfo isReadOnly = attr.GetType().GetField(
        "isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);

isReadOnly.SetValue(attr, false);

这种方法运行得很好但不幸的是也仅在类级别上。这意味着,如果我将Value的{​​{1}}设置为isReadOnly我的false的所有 - 对象都具有Parameter属性可写的。但我只希望这个特定的对象(因此对象级)。我真的不想为读/写和只读属性创建单独的类。

由于我的想法不足,非常感谢您的帮助:)

提前致谢!

编辑:我需要将readonly属性显示为灰色,这样用户就可以看到不允许或不可能编辑它们。

2 个答案:

答案 0 :(得分:5)

编辑:已删除链接文章(我希望只是暂时的)。你可以在How to add property-level Attribute to the TypeDescriptor at runtime?的答案中找到可行的替代方案。基本上,您必须通过ReadOnlyAttribute为该属性添加(在运行时)TypeDescriptor

<小时/> 看看这个古老而又不错的article on CodeProject,它包含了PropertyGrid的许多有用的工具

基本上,您提供了一个用于获取属性属性的类或委托。因为它将被调用传递您想要获取属性的对象的实例,所以您将能够以每个对象为基础返回(或不返回)ReadOnlyAttribute。简而言之:将PropertyAttributesProviderAttribute应用于您的属性,编写您自己的提供程序并根据对象本身(而不是类)替换PropertyAttributes集合中的属性

答案 1 :(得分:1)

您可以使用自定义类型描述符包装对象,但我认为这样会有点过分,因为您必须创建一个新的typedescriptor派生类。

因此,最简单的解决方案是拥有一个标志,例如:

public class Parameter 
{ 
    private string thevalue;

    [Browsable(false)]
    public bool CanEditValue { get; set; }

    [Description("the name")] 
    public string Name { get; set; } 

    [Description("the description")] 
    public string Description { get; set; }

    [Description("the value"), ReadOnly(true)] 
    public string Value { 
        get { return this.thevalue; }
        set { if (this.CanEditValue) this.thevalue = value; } 
    }
}