动态设置PropertyGrid中属性的只读属性

时间:2013-10-28 17:03:53

标签: c# .net winforms readonly propertygrid

我有一个PropertyGrid,我用它来显示辅助类中的属性。我将助手类分配给PropertyGrid,如下所示:

myPropertyGrid.SelectedObject = mySettingsHelper;

在帮助器类中,我在设计时分配ReadOnlyAttribute,如下所示:

[DisplayName("DisplayExA"),
Description("DescriptionExA"),
ReadOnlyAttribute(true)]
public string PropertyA { get; set; }

[DisplayName("DisplayExB"),
Description("DescriptionExB"),
ReadOnlyAttribute(false)]
public string PropertyB { get; set; }

[DisplayName("DisplayExC"),
Description("DescriptionExC"),
ReadOnlyAttribute(true)]
public string PropertyC { get; set; }

但是现在我需要能够在运行时动态地更改各个属性的这个属性。根据某些标准,这些属性中的一些可能需要是只读的或不是只读的。如何在运行时动态更改?

编辑:

我尝试了以下代码,但这为对象的每个实例设置了ReadOnly属性!我想按对象做。有时,一个对象可能具有PropertyA只读,而第二个对象的PropertyA不是只读的。

public static class PropertyReadOnlyHelper
{
    public static  void SetReadOnly(object container, string name, bool value)
    {
        try
        {
            PropertyDescriptor descriptor = TypeDescriptor.GetProperties(container.GetType())[name];
            ReadOnlyAttribute attribute = (ReadOnlyAttribute)descriptor.Attributes[typeof(ReadOnlyAttribute)];
            FieldInfo fieldToChange = attribute.GetType().GetField("isReadOnly",
                                                System.Reflection.BindingFlags.NonPublic |
                                                System.Reflection.BindingFlags.Instance);
            fieldToChange.SetValue(attribute, value);
        }
        catch { }
    }
}

5 个答案:

答案 0 :(得分:1)

我能够使用此CodeProject文章中的库完全按照我的需要(对象级别分配只读属性)。有趣的是它使我仍然可以使用.NET PropertyGrid并只使用自定义属性来处理动态设置。

答案 1 :(得分:0)

使用反射来获取ReadOnlyAttribute类的实例引用,然后在该实例上切换IsReadOnly属性。最后,如果需要,通过将其SelectedObjects设置为null然后重置它,重新选择PropertyGrid中的项。您也许可以使用PropertyGrid RefreshTabs方法执行此操作,我不确定。

编辑:

不幸的是,IsReadOnly属性本身是只读的...在这种情况下,我们必须使用反射来更改IsReadOnly属性的支持字段的值。

答案 2 :(得分:0)

添加Readonly

TextBoxID.Attributes.Add("readonly","true");

删除只读

TextBoxID.Attributes.Remove("readonly");

答案 3 :(得分:0)

经常需要一起在PropertyGrid中动态设置属性的可浏览只读属性,它们也是类似的工作

触摸几下之后, Reza Aghaei 关于“ Hide some properties in PropertyGrid at run-time”的好答案也适用于操纵readonly属性。

public class CustomObjectWrapper : CustomTypeDescriptor
{
    public object WrappedObject { get; private set; }
    public List<string> BrowsableProperties { get; private set; }
    public List<string> ReadonlyProperties { get; private set; }

    public CustomObjectWrapper(object o)
        : base(TypeDescriptor.GetProvider(o).GetTypeDescriptor(o))
    {
        WrappedObject = o;
        BrowsableProperties = new List<string>() { "Text", "BackColor" };
        ReadonlyProperties = new List<string>() { "Font" };
    }
    public override PropertyDescriptorCollection GetProperties()
    {
        return this.GetProperties(new Attribute[] { });
    }
    public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        List<PropertyDescriptor> result = new List<PropertyDescriptor>();

        IEnumerable<PropertyDescriptor> properties = base.GetProperties(attributes).Cast<PropertyDescriptor>()
            .Where(p => BrowsableProperties.Contains(p.Name));//unbrowsable filtering

        foreach (var p in properties)
        {
            PropertyDescriptor resultPropertyDescriptor = null;

            //handle being readonly 
            if (ReadonlyProperties.Contains(p.Name))
            {
                List<Attribute> atts = p.Attributes.Cast<Attribute>().ToList();
                atts.RemoveAll(a => a.GetType().Equals(typeof(ReadOnlyAttribute)));//remove any readonly attribute
                atts.Add(new ReadOnlyAttribute(true));//add "readonly=true" attribute

                resultPropertyDescriptor = TypeDescriptor.CreateProperty(WrappedObject.GetType(), p, atts.ToArray());
            }
            else
            {
                resultPropertyDescriptor = TypeDescriptor.CreateProperty(WrappedObject.GetType(), p, p.Attributes.Cast<Attribute>().ToArray());
            }

            if (resultPropertyDescriptor != null)
                result.Add(resultPropertyDescriptor);

        }

        return new PropertyDescriptorCollection(result.ToArray());
    }
}

及其用法:

propertyGrid1.SelectedObject = new CustomObjectWrapper(myobject);

答案 4 :(得分:0)

Please try the code below.


  
[CategoryAttribute("2. LINE"), DisplayNameAttribute("Spline Line Tension"),
 DescriptionAttribute("Chart's Spline Line Tension "), ReadOnlyAttribute(false)]
public float _PG_SplineTension
{
    get
    {
        bool lbReadyOnly = true;
        SetPropertyReadOnly("_PG_SplineTension", lbReadyOnly);
        return this.cfSplineTension;
   }
    set { this.cfSplineTension = value; }
}



private void SetPropertyReadOnly(string lsProperty, bool lbIsReadOnly)
{
    PropertyDescriptor descriptor = TypeDescriptor.GetProperties(this.GetType())[lsProperty];
    ReadOnlyAttribute attribute = (ReadOnlyAttribute)

    descriptor.Attributes[typeof(ReadOnlyAttribute)];
    FieldInfo fieldToChange = attribute.GetType().GetField("isReadOnly",
        System.Reflection.BindingFlags.NonPublic |
        System.Reflection.BindingFlags.Instance);
    fieldToChange.SetValue(attribute, lbIsReadOnly);
}