兩點C#的propertyGrid的使用心得


最近接觸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進行修改之后被調用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM