• 两点C#的propertyGrid的使用心得【转】


    源文:http://www.cnblogs.com/bicker/p/3318934.html

    最近接触C#的PropertyGrid比较多,得到了两个小心得记录一下。

    第1点是关于控制PropertyGrid中属性的只读属性的。

    我遇到的问题是这样的,我需要在运行时根据SVN的状态动态控制PropertyGrid中的属性的读写控制。以前的做法比较简单,直接是 PropertyGrid.Enabled(false)。这样的坏处是完全使Grid完全失效,连滚动条也不可用了,不便于查看属性。后来上网查阅相关 的资料,网上有比较的是同一篇文章的复制,原文出处我已经找不到了。先把原文贴出来如下:

    大家知道在类的某个属性中加[ReadOnlyAttribute(true)]声明标记后,此类的对象的这个属性在PropertyGrid中就表现为灰色不可更改,请问大家有没有什么办法动态地让这个属性在PropertyGrid中的显示变为可读写么?   
      以下的方法试过,不好用   
      1、想在程序里改声明标记,可是不行   
      2、另外写个类,同样的属性标记为[ReadOnlyAttribute(false)],然后重新selectobject,可是太复杂了。   

    用反射可以实现动态改变,只读、可见等等,这些属性都可以改变。   

      以下两个方法分别实现可见性和只读属性的动态改变:   

      void   SetPropertyVisibility(object   obj,   string   propertyName,   bool   visible)   
      {   
      Type   type   =   typeof(BrowsableAttribute);   
      PropertyDescriptorCollection   props   =   TypeDescriptor.GetProperties(obj);   
      AttributeCollection   attrs   =   props[propertyName].Attributes;   
      FieldInfo   fld   =   type.GetField("browsable",   BindingFlags.Instance   |   BindingFlags.NonPublic);   
      fld.SetValue(attrs[type],   visible);   
      }   

      void   SetPropertyReadOnly(object   obj,   string   propertyName,   bool   readOnly)   
      {   
      Type   type   =   typeof(System.ComponentModel.ReadOnlyAttribute);   
      PropertyDescriptorCollection   props   =   TypeDescriptor.GetProperties(obj);   
      AttributeCollection   attrs   =   props[propertyName].Attributes;   
      FieldInfo   fld   =   type.GetField("isReadOnly",   BindingFlags.Instance   |   BindingFlags.NonPublic   |   BindingFlags.CreateInstance);   
      fld.SetValue(attrs[type],   readOnly);   
      }

    使用时,SetPropertyVisibility(obj,   "名称",   true);   
      obj指的就是你的SelectObject,   “名称”是你SelectObject的一个属性   
      当然,调用这两个方法后,重新SelectObject一下,就可以了

    心得:

    (1)如果对属性框中所有属性一起进行控制,可以不添加 [ReadOnlyAttribute(false)]标记,propertyName可以是任何属性名称。[注:这里讲得很不清楚]

    (2)如果仅仅对某一个属性进行控制,则必须在每个属性的描述中添加 [ReadOnlyAttribute(false)]标记。propertyName必须是所要控制的属性名。

    原文中提到的思路是在运行时,通过反射的方式修改每一个Property的ReadOnlyAttribute。只是心得那里説不很不清楚,要对整个对象而非具体的属性进行控制时怎么办。

    我的第一个想法是遍历所有的Property,对每一个都设置ReadOnly,但是这样是错误的,而且有副作用。后来经过试验,我直接对PropertyGrid的Object设置ReadOnly。

    复制代码
    1 private void button1_Click(object sender, EventArgs e)
    2         {
    3             Type readonlyType = typeof(System.ComponentModel.ReadOnlyAttribute);
    4             PropertyDescriptorCollection props = TypeDescriptor.GetProperties(propertyGrid1.SelectedObject);
    5             FieldInfo fld = readonlyType.GetField("isReadOnly", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.CreateInstance);
    6             AttributeCollection attrs = TypeDescriptor.GetAttributes(propertyGrid1.SelectedObject);
    7             fld.SetValue(attrs[typeof(ReadOnlyAttribute)], gridReadOnly);
    8             gridReadOnly = !gridReadOnly;
    9         }
    复制代码

     这里説一下,在找解决办法的时候,还去顺便了解了一下c#在运行时,动态添加Attribute的内容,这个内容留下次再记录好了。

    还找到一篇讲反射可以通过FieldInfo.SetValue设置任何字段的值的文章:http://www.cnblogs.com/Laser_Lu/archive/2004/08/01/29171.html

    第2点是PropertyGrid中使用TypeConverter

    PropertyGrid中对于自定义的类型显示支持有限,最好是自己去实现自己的TypeConverter,把类型转换来进行显示。我写了一个简单的例子,把List类型转换成string。

    复制代码
     1 public class MyColorConverter : TypeConverter
     2     {
     3         public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
     4         {
     5             if (value == null)
     6             {
     7                 return new List<int>();
     8             }
     9             string stringValue = value as string;
    10             if (stringValue != null)
    11             {
    12                 List<int> result = new List<int>();
    13                 string[] vs = stringValue.Split(new char[] { ',' });
    14                 foreach (string eachString in vs)
    15                 {
    16                     result.Add(int.Parse(eachString));
    17                 }
    18                 return result;
    19             }
    20             else
    21             {
    22                 return base.ConvertFrom(context, culture, value);
    23             }
    24         }
    25 
    26         public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, Type destinationType)
    27         {
    28             if (destinationType == typeof(string))
    29             {
    30                 return true;
    31             }
    32             return base.CanConvertTo(context, destinationType);
    33         }
    34 
    35         public override System.ComponentModel.PropertyDescriptorCollection GetProperties(System.ComponentModel.ITypeDescriptorContext context, object value, System.Attribute[] attributes)
    36         {
    37             throw new Exception("The method or operation is not implemented.");
    38         }
    39 
    40         public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    41         {
    42             if (destinationType == typeof(string))
    43             {
    44                 List<int> list = value as List<int>;
    45                 if (list != null && list.Count > 0)
    46                 {
    47                     StringBuilder sb = new StringBuilder();
    48                     foreach (int v in list)
    49                     {
    50                         sb.AppendFormat("{0},", v);
    51                     }
    52                     sb.Remove(sb.Length - 1, 1);
    53                     return sb.ToString();
    54                 }
    55                 return "";
    56             }
    57             else
    58             {
    59                 return base.ConvertTo(context, culture, value, destinationType);
    60             }
    61         }
    62 
    63         public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType)
    64         {
    65             if (sourceType == typeof(string))
    66             {
    67                 return true;
    68             }
    69             return base.CanConvertFrom(context, sourceType);
    70         }
    71     }
    复制代码
    复制代码
         private List<int> color1 = new List<int>();
            [Category("main")]
            [DisplayName("颜色1")]
            [TypeConverter(typeof(MyColorConverter))]
            public List<int> Color1
            {
                get { return color1; }
                set { color1 = value; }
            }
    复制代码

    ConvertFrom函数会在PropertyGrid中的字符串被修改保存后被调用

    ConvertTo函数则是在最初显示PropertyGrid以及对List进行修改之后被调用

  • 相关阅读:
    一台电脑上的git同时使用两个github账户
    git自己操作命令组集合
    git基本原理
    js如何遍历表单所有控件
    js如何访问表单(四种方法)(博客园+li的方式去掉p标签)
    js如何操作表格(常用属性方法汇总)
    php数学和时间常用函数有哪些(总结表)(看学习视频效率挺高的)(复习)
    swift 笔记 (十九) —— 协议
    ecshop广告调用方法
    K60 启动过程分析
  • 原文地址:https://www.cnblogs.com/mazhenyu/p/4613165.html
Copyright © 2020-2023  润新知