对象级别上的PropertyGrid只读属性

9
我希望在我的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”的“isReadOnly”设置为“false”,所有我的“Parameter”对象的“Value”属性都可写。但我只想在特定对象(因此是对象级别)上实现这一点。我真的不想为只读和可读属性创建不同的类。
由于我已经没有更多的想法,非常感谢你的帮助 :)
提前致谢!
编辑:我需要将只读属性灰色显示,以便用户可以看到它们不允许或不可能进行编辑。
2个回答

5
EDIT: 链接的文章已被删除(我希望只是暂时的)。你可以在这个问题的回答中找到一个可行的替代方案。基本上,你需要通过TypeDescriptor为该属性添加(运行时)ReadOnlyAttribute
看看这篇旧但不错的CodeProject文章,它包含了许多有用的用于PropertyGrid的工具。
基本上,你提供一个类或委托,用于获取你的属性的属性。因为它将被调用并传递你想要获取属性的对象实例,那么你将能够以每个对象为基础返回(或不返回)ReadOnlyAttribute。简而言之:将PropertyAttributesProviderAttribute应用于你的属性,编写自己的提供程序,并根据对象本身而不是类替换PropertyAttributes集合中的属性。

1
我已经阅读了整个文档,但仍然不理解你的想法。你能否提供一个小的代码示例来使它更清楚一些?谢谢你的时间 :) - reflective_mind
1
根据我在源代码中所看到的,这需要使用作者自定义的PropertyGrid实现才能使其正常工作?在我的情况下,我必须使用现有的PropertyGrid,该Grid位于DLL中(我无法修改)。 - reflective_mind
1
终于找到了解决办法。我忘记在类的顶部放置TypeConverterAttribute了。解决一个小问题需要这么多代码...但最重要的是现在它可以工作了。谢谢! - reflective_mind
该CodeProject文章已于2014年12月8日被删除 =/ - Patrik
好的(但我承认我不知道如何在SO上开始聊天...) - Adriano Repetti
显示剩余2条评论

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

你好 Jaime,你提出的双倍属性建议是可以接受的,因为它非常简单。我尝试了一下,不幸的是,在 setter 中进行检查并不能像 ReadOnly(true) 一样禁用属性编辑...所以它不会变灰。用户会认为它是可更改的,但他们的输入将被丢弃。还有其他不那么复杂的想法吗? :) - reflective_mind
我担心你唯一的选择是派生一个属性描述符并实现条件IsReadOnly属性getter。 - user694833

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接