代码之家  ›  专栏  ›  技术社区  ›  Sameh

.Net如何为usercontrol的属性设置IsReadOnly

  •  1
  • Sameh  · 技术社区  · 6 年前

    我在中有一个用户控件。有2个新属性的NET

    Prop1: Boolean
    Prop2: String
    

    我想 项目2 只读 当用户设置 项目1 错误 .

    enter image description here

    3 回复  |  直到 6 年前
        1
  •  7
  •   Reza Aghaei    5 年前

    如果要根据某些条件在运行时使属性外观为只读(灰色),则需要指定 CustomTypeDescriptor 为属性网格提供有关类的元数据的类。

    PropertyGrid 控件使用对象的类型描述符提取有关要显示的属性的信息。类型描述符返回 PropertyDescriptor 对象作为属性列表。每个 属性描述器 包含一些方法和属性,用于返回显示名称、说明和有关属性的其他信息。 IsReadOnly 的属性 属性描述器 负责通知 属性表格 如果属性应为只读。

    实例

    在下面的示例中,我创建了一个包含两个属性的类。 Editable StringProperty . 如果 可编辑 true 然后 StringProperty属性 是可编辑的,否则它将是只读的,并在中显示为灰色 属性表格 .

    MyPropertyDescriptor

    它负责为属性提供元数据。在实现此类时,对于大多数属性,我们将使用使用原始属性实现的普通实现,但对于 IsReadOnly公司 我们将根据 可编辑 所有者对象的属性:

    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属性 我们将在运行时更改其行为,我们将返回 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

    当有人(如属性网格)请求类型描述时,它负责返回对象的类型描述符:

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

    样本类别

    最后,该类的实现:

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

    后果

    enter image description here

    进一步阅读

    您可以在以下帖子中阅读其他一些解决方案:

        2
  •  0
  •   Sameh    6 年前

    非常感谢@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(roaccount,true | false);

    非常感谢。

        3
  •  0
  •   Himal Patel    6 年前

    请确保在名为“可编辑”的属性上具有以下属性

    [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
    

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