簡體   English   中英

在 PropertyGrid 中動態設置屬性的只讀屬性

[英]Dynamically set readonly attribute of properties in a PropertyGrid

我有一個PropertyGrid ,用於在助手 class 中顯示屬性。我將助手 class 分配給PropertyGrid ,如下所示:

myPropertyGrid.SelectedObject = mySettingsHelper;

在助手 class 中,我在設計時分配了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; }

但是現在我需要能夠在運行時動態地更改各個屬性的這個屬性。 根據某些標准,其中一些屬性可能需要是只讀的或不是只讀的。 我將如何在運行時動態地進行更改?

編輯:

我嘗試了以下代碼,但這為 object 的每個實例設置了 ReadOnly 屬性。我想按照 object 執行此操作。有時一個 object 可能具有只讀屬性,而第二個 object 具有非只讀屬性。

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

使用此CodeProject文章中的庫,我能夠完全滿足我的需要(只讀屬性的對象級分配)。 好的是它使我仍然可以使用 .NET PropertyGrid並且只使用自定義屬性來處理動態設置。

使用反射獲取ReadOnlyAttribute類的實例引用,然后切換該實例的IsReadOnly屬性。 最后,如果需要,通過將其 SelectedObjects 設置為 null 然后重新設置它來重新選擇 PropertyGrid 中的項目。 您也可以使用 PropertyGrid RefreshTabs方法來執行此操作,我不確定。

編輯:

不幸的是 IsReadOnly 屬性本身是只讀的……在這種情況下,我們必須使用反射來更改 IsReadOnly 屬性的支持字段的值。

添加只讀

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

刪除只讀

TextBoxID.Attributes.Remove("readonly");

在 PropertyGrid 中動態設置屬性的可瀏覽只讀屬性通常需要一起使用,它們也是類似的工作

經過幾次接觸, Reza Aghaei關於“ 在運行時隱藏 PropertyGrid 中的一些屬性”的精彩回答也適用於操作只讀屬性。

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

非常感謝。 根據答案,我提供了以下可以正常工作的代碼:

private void SetReadonly ( object o, bool value )
{
  foreach ( PropertyInfo property in o.GetType().GetProperties() )
    if ( property.GetCustomAttribute<ReadOnlyAttribute>() != null )
    {
      Attribute readOnly = TypeDescriptor.GetProperties( o.GetType() )[property.Name].Attributes[typeof( ReadOnlyAttribute )];
      readOnly.GetType().GetField( nameof( ReadOnlyAttribute.IsReadOnly ), BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase ).SetValue( readOnly, value );
    }
}

查看此頁面:
https://www.codeproject.com/Articles/152945/Enabling-disabling-properties-at-runtime-in-the-Pr

引用上面的帖子:

將 class 的每個屬性的 ReadOnly 屬性靜態定義為您想要的任何值非常重要。 否則,以這種方式在運行時更改屬性將錯誤地修改 class 的每個屬性的屬性。

使用反射在運行時修改目標屬性的“ReadOnly”屬性來達到你的目的。 設置一個屬性適用於所有屬性的問題是因為您需要在同一個 PropertyGrid object 中顯式設置具有 ReadOnly 屬性的所有屬性以避免該問題。

[RefreshProperties(System.ComponentModel.RefreshProperties.All)]
[ReadOnly(false)]
public string Country
{
  get { return mCountry; }
  set
      {
      mCountry = value;
      PropertyDescriptor descriptor = TypeDescriptor.GetProperties(this.GetType())["State"];
      ReadOnlyAttribute attribute = (ReadOnlyAttribute)
                                    descriptor.Attributes[typeof(ReadOnlyAttribute)];
      FieldInfo fieldToChange = attribute.GetType().GetField("isReadOnly", 
                                       System.Reflection.BindingFlags.NonPublic | 
                                       System.Reflection.BindingFlags.Instance);
      fieldToChange.SetValue(attribute, mCountry != "U.S.");
      }
}

[ReadOnly(true)]
public string State
{
   get { return mState; }
   set { mState = value; }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM