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

Sam*_*meh 1 .net c# vb.net user-controls winforms

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

Prop1: Boolean
Prop2: String
Run Code Online (Sandbox Code Playgroud)

当用户将Prop1设置为false时,我想在属性网格中创建Prop2 READONLY.

在此输入图像描述

Rez*_*aei 6

如果要根据某些条件在运行时使属性外观为只读(灰色),则需要CustomTypeDescriptor为您的类分配一个类,该类提供有关属性网格的类的元数据.

PropertyGridcontrol使用对象的类型描述符来提取有关其要显示的属性的信息.类型描述符返回PropertyDescriptor对象列表作为属性列表.每个PropertyDescriptor包含一些方法和属性,以返回显示名称,描述和有关该属性的其他信息.如果财产应该是只读IsReadOnly的,PropertyDescriptor则负责通知PropertyGrid财产.

在以下示例中,我创建了一个包含两个属性的类.EditableStringProperty.如果Editable是,true那么它StringProperty是可编辑的,否则它将是只读的,并将显示为灰色PropertyGrid.

MyPropertyDescriptor

它负责提供财产的元数据.在实现这个类时,对于大多数属性,我们将使用使用原始属性的实现的简单实现,但是IsReadOnly我们将根据Editable所有者对象的属性值来决定:

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; } }
}
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

SampleClass

最后,该类的实现:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

结果

在此输入图像描述

进一步阅读

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

  • 我的第一次尝试是从属性描述符的Attributes集合中删除现有的ReadOnly属性并添加一个新属性.(它没有任何风险)但令人惊讶的是,财产消失了.然后我决定更新这个值.如果由于任何原因我无法解决删除/添加ReadOnly属性的问题,可能我将更改Post而不是使用PropertyDescriptor,将使用`ReadOnly`属性修饰属性并将使用反射更改它(这不会没有任何风险.) (3认同)
  • @IvanStoev更新了`SetReadOnlyAttribute`扩展方法,从`AttributesArray`中删除现有的`ReadOnly`属性,并添加一个新的`ReadOnly`属性.因此静态值不再存在风险.感谢分享关注! (3认同)