.Net 如何为用户控件的 属性 设置 IsReadOnly

.Net how to set IsReadOnly for a property for a usercontrol

我在 .NET 中有一个用户控件,其中有 2 个新 属性

Prop1: Boolean
Prop2: String

当用户设置 Prop1[ 时,我想在 属性 网格中使 Prop2 READONLY =23=] 到 false.

如果您想根据某些条件在 运行 时将 属性 外观设置为只读(灰色),您需要将 CustomTypeDescriptor 分配给您的 class 为 属性 网格提供有关 class 的元数据。

PropertyGrid control uses the type descriptor of the object to extract information about its properties to show. The type descriptor, returns a list of PropertyDescriptor 个对象作为属性列表。每个 PropertyDescriptor 包含一些方法和属性以 return 显示名称、描述和有关 属性 的其他信息。 PropertyDescriptorIsReadOnly 属性 负责通知 PropertyGrid 是否 属性 应该是只读的。

例子

在下面的示例中,我创建了一个包含两个属性的 class。 EditableStringProperty。如果 Editabletrue 那么 StringProperty 是可编辑的,否则它将是只读的并且在 PropertyGrid.

中显示为灰色

我的属性描述符

它负责为 属性 提供元数据。在实现此 class 时,对于大多数属性,我们将使用使用原始 属性 实现的简单实现,但对于 IsReadOnly 我们将根据 [=21= 的值来决定] 属性 所有者对象:

using System;
using System.ComponentModel;
using System.Linq;
public class MyPropertyDescriptor : PropertyDescriptor
{
    PropertyDescriptor p;
    SampleClass o;
    public MyPropertyDescriptor(PropertyDescriptor originalProperty, SampleClass owenr)
        : base(originalProperty) { p = originalProperty; o = owenr; }
    public override bool CanResetValue(object component)
    { return p.CanResetValue(component); }
    public override object GetValue(object component) { return p.GetValue(component); }
    public override void ResetValue(object component) { p.ResetValue(component); }
    public override void SetValue(object component, object value)
    { p.SetValue(component, value); }
    public override bool ShouldSerializeValue(object component)
    { return p.ShouldSerializeValue(component); }
    public override AttributeCollection Attributes { get { return p.Attributes; } }
    public override Type ComponentType { get { return p.ComponentType; } }
    public override bool IsReadOnly { get { return !o.Editable; } }
    public override Type PropertyType { get { return p.PropertyType; } }
}

MyTypeDescriptor

它负责提供对象的属性列表。对于 StringProperty,我们将在 运行 时更改其行为,我们将 return a MyPropertyDescriptor:

using System;
using System.ComponentModel;
using System.Linq;
public class MyTypeDescriptor : CustomTypeDescriptor
{
    ICustomTypeDescriptor d;
    SampleClass o;
    public MyTypeDescriptor(ICustomTypeDescriptor originalDescriptor, SampleClass owner)
        : base(originalDescriptor) { d = originalDescriptor; o = owner; }
    public override PropertyDescriptorCollection GetProperties()
    { return this.GetProperties(new Attribute[] { }); }
    public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        var properties = base.GetProperties(attributes).Cast<PropertyDescriptor>()
            .Select(p => p.Name == "StringProperty" ? new MyPropertyDescriptor(p, o) : p)
            .ToArray();
        return new PropertyDescriptorCollection(properties);
    }
}

MyTypeDescriptionProvider

它负责 return 你的对象的类型描述符,当有人(比如 属性 grid)请求类型描述时:

using System;
using System.ComponentModel;
public class MyTypeDescriptionProvider : TypeDescriptionProvider
{
    public MyTypeDescriptionProvider()
        : base(TypeDescriptor.GetProvider(typeof(object))) { }

    public override ICustomTypeDescriptor GetTypeDescriptor(Type type, object o)
    {
        ICustomTypeDescriptor baseDescriptor = base.GetTypeDescriptor(type, o);
        return new MyTypeDescriptor(baseDescriptor, (SampleClass)o);
    }
}

样本类

最后,class的执行:

using System;
using System.ComponentModel;
[TypeDescriptionProvider(typeof(MyTypeDescriptionProvider))]
public class SampleClass
{
    [RefreshProperties(RefreshProperties.All)]
    public bool Editable { get; set; }
    string sp;
    public string StringProperty
    {
        get { return sp; }
        set
        {
            if (Editable)
                sp = value;
        }
    }
}

结果

进一步阅读

您可以阅读以下内容中的一些其他解决方案 post:

非常感谢@reza-aghaei, 根据您的详细回答和@Ivan 评论,以下代码段解决了我的问题:

Dim captionFld = TypeDescriptor.GetProperties(Me)("Caption")
Dim roaCaption = captionFld.Attributes.OfType(Of ReadOnlyAttribute)().FirstOrDefault
roaCaption.GetType().GetField("isReadOnly", BindingFlags.NonPublic Or BindingFlags.Instance).SetValue(roaCaption, True)

或 C#

var captionFld = TypeDescriptor.GetProperties(this)["Caption"];
var roaCaption = captionFld.Attributes.OfType(Of, ReadOnlyAttribute)[].FirstOrDefault;
roaCaption.GetType().GetField("isReadOnly", (BindingFlags.NonPublic | BindingFlags.Instance)).SetValue(roaCaption, true);

您可以更改 .SetValue(roaCaption, true|false);

非常感谢。

请确保您在名为 "Editable"

的 属性 上具有以下属性
[RefreshProperties(System.ComponentModel.RefreshProperties.All)]

添加以下方法,并从"Editable"属性的setter调用它,并传递属性的名称以设置只读。

    public void EnableDisableProperty(string PropertyName,bool IsReadOnly)
    {
        PropertyDescriptor _propDescriptor = TypeDescriptor.GetProperties(this.GetType())[PropertyName];
        ReadOnlyAttribute _readOnlyAttribute = (ReadOnlyAttribute)
                                      _propDescriptor.Attributes[typeof(ReadOnlyAttribute)];

        FieldInfo _fieldToChange = _readOnlyAttribute.GetType().GetField("isReadOnly",
                                         System.Reflection.BindingFlags.NonPublic |
                                         System.Reflection.BindingFlags.Instance);
        _fieldToChange.SetValue(_readOnlyAttribute, IsReadOnly);
    }