C#自定义PropertyGrid属性

Posted jjhua

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#自定义PropertyGrid属性相关的知识,希望对你有一定的参考价值。

最近用到了PropertyGrid,原来从来没用到过,拿在手里,一头雾水,经过一段时间研究后,大概理解了Property的使用方法,下面仔细剖析一下。

PropertyGrid控件就是Visual Studio开发工具里面的属性浏览器,我们在VS里面可以通过属性浏览器查看,修改控件的属性,并主要通过使用反射来检索项目的属性。

一.如何显示属性

1)普通显示

在PropertyGrid中显示属性很容易,我们可以直接给propertyGrid1.SelectedObject属性赋值,SelectObject属性可以获取或设置当前选定的对象,数据类型为object,这就意味着我们可以直接将一个对象赋给它。针对一个对象,它会将对象中的所有公共属性显示在PropertyGrid上。假如我们定义一个Station类,如下

[csharp] view plain copy print ?
  1. public class Station   
  2.      
  3.        private string _StationName;  
  4.        private double _Lon = 103;  
  5.        private double _Lat = 38;  
  6.        private Color _color;  
  7.        private string _file = string.Empty;  
  8.        private Font _font;  
  9.        public string FileName  
  10.          
  11.            get  return _file;   
  12.            set  _file = value;   
  13.          
  14.        public Color Color  
  15.          
  16.            get  return _color;   
  17.            set  _color = value;   
  18.          
  19.        public Font Font  
  20.          
  21.            get  return _font;   
  22.            set  _font = value;   
  23.          
  24.        public string StationName  
  25.          
  26.            get  return _StationName;   
  27.            set  _StationName = value;   
  28.          
  29.        public double Lon  
  30.          
  31.            get  return _Lon;   
  32.            set  _Lon = value;   
  33.          
  34.        public double Lat  
  35.          
  36.            get  return _Lat;   
  37.            set  _Lat = value;   
  38.          
  39.      
 public class Station 
    
        private string _StationName;
        private double _Lon = 103;
        private double _Lat = 38;
        private Color _color;
        private string _file = string.Empty;
        private Font _font;
        public string FileName
        
            get  return _file; 
            set  _file = value; 
        
        public Color Color
        
            get  return _color; 
            set  _color = value; 
        
        public Font Font
        
            get  return _font; 
            set  _font = value; 
        
        public string StationName
        
            get  return _StationName; 
            set  _StationName = value; 
        
        public double Lon
        
            get  return _Lon; 
            set  _Lon = value; 
        
        public double Lat
        
            get  return _Lat; 
            set  _Lat = value; 
        
    

然后在窗体中拖拉一个PropertyGrid控件propertygrid1,在Form_load中代码如下

[csharp] view plain copy print ?
  1. private void Form1_Load(object sender, EventArgs e)  
  2.   
  3.   Station s=new Station();  
  4.   propertygrid1.SelectObject=s;  
  5.   
        private void Form1_Load(object sender, EventArgs e)
        
          Station s=new Station();
          propertygrid1.SelectObject=s;
        
我们就可以看到如下效果:


我们看到属性名显示都是英文,那样很不方便阅读如果我们像显示中文,该如何实现呢?

更改了显示方式

要更改某些属性的显示方式,您可以对这些属性应用不同的特性。特性是用于为类型、字段、方法和属性等编程元素添加批注的声明标记,在运行时可以使用反射对其进行检索。下面列出了其中的一部分:

DescriptionAttribute - 设置显示在属性下方说明帮助窗格中的属性文本。这是一种为活动属性(即具有焦点的属性)提供帮助文本的有效方法。

CategoryAttribute - 设置属性在网格中所属的类别。当您需要将属性按类别名称分组时,此特性非常有用。如果没有为属性指定类别,该属性将被分配给杂项 类别。可以将此特性应用于所有属性。

BrowsableAttribute –  表示是否在网格中显示属性。此特性可用于在网格中隐藏属性。默认情况下,公共属性始终显示在网格中。

ReadOnlyAttribute –  表示属性是否为只读。此特性可用于禁止在网格中编辑属性。默认情况下,带有 get 和 set 访问函数的公共属性在网格中是可以编辑的。

DefaultValueAttribute –  表示属性的默认值。如果希望为属性提供默认值,然后确定该属性值是否与默认值相同,则可使用此特性。可以将此特性应用于所有属性。

DefaultPropertyAttribute –  表示类的默认属性。在网格中选择某个类时,将首先突出显示该类的默认属性。

下面我们在Station类中的属性Lon上方添加[CategoryAttribute("坐标"),DisplayNameAttribute("经度")],效果如下:


如果想要在属性表中添加颜色选择和字体选择那是很容易一件事,可以在Station类中添加Color类型属性,和Font类型属性,绑定后,就可以进行颜色选择和字体选择了,代码在Station中已经实现。

2)自定义显示

我们可以看出这种上面这种显示属性方法并不够灵活,我们不能方便的及时增加或者删除属性。

   //属性表管理类

[csharp] view plain copy print ?
  1. <span style="font-size: 13px;"public class PropertyManageCls : CollectionBase, ICustomTypeDescriptor  
  2.       
  3.         public void Add(Property value)  
  4.           
  5.             int flag=-1;  
  6.             if (value != null)  
  7.               
  8.                 if (base.List.Count>0)  
  9.                   
  10.                     IList <Property> mList=new List<Property>();  
  11.                     for (int i = 0; i < base.List.Count; i++)  
  12.                       
  13.                         Property p = base.List[i] as Property;  
  14.                         if (value.Name == p.Name)  
  15.                           
  16.                             flag = i;  
  17.                           
  18.                         mList.Add(p);  
  19.                       
  20.                     if (flag == -1)  
  21.                       
  22.                         mList.Add(value);  
  23.                       
  24.                     base.List.Clear();  
  25.                     foreach (Property p in mList)  
  26.                       
  27.                         base.List.Add(p);  
  28.                       
  29.                   
  30.                 else  
  31.                   
  32.                     base.List.Add(value);  
  33.                   
  34.               
  35.           
  36.         public void Remove(Property value)  
  37.           
  38.             if(value!=null&&base.List.Count>0)  
  39.             base.List.Remove(value);  
  40.           
  41.         public Property this[int index]  
  42.           
  43.             get  
  44.               
  45.                 return (Property)base.List[index];  
  46.               
  47.             set  
  48.               
  49.                 base.List[index] = (Property)value;  
  50.               
  51.           
  52.         #region ICustomTypeDescriptor 成员  
  53.         public AttributeCollection GetAttributes()  
  54.           
  55.             return TypeDescriptor.GetAttributes(this,true);  
  56.           
  57.         public string GetClassName()  
  58.           
  59.             return TypeDescriptor.GetClassName(thistrue);  
  60.           
  61.         public string GetComponentName()  
  62.           
  63.             return TypeDescriptor.GetComponentName(thistrue);  
  64.           
  65.         public TypeConverter GetConverter()  
  66.           
  67.             return TypeDescriptor.GetConverter(thistrue);  
  68.           
  69.         public EventDescriptor GetDefaultEvent()  
  70.           
  71.             return TypeDescriptor.GetDefaultEvent(thistrue);  
  72.           
  73.         public PropertyDescriptor GetDefaultProperty()  
  74.           
  75.             return TypeDescriptor.GetDefaultProperty(thistrue);  
  76.           
  77.         public object GetEditor(Type editorBaseType)  
  78.           
  79.             return TypeDescriptor.GetEditor(this, editorBaseType, true);  
  80.           
  81.         public EventDescriptorCollection GetEvents(Attribute[] attributes)  
  82.           
  83.             return TypeDescriptor.GetEvents(this, attributes, true);  
  84.           
  85.         public EventDescriptorCollection GetEvents()  
  86.           
  87.             return TypeDescriptor.GetEvents(this,true);  
  88.           
  89.         public PropertyDescriptorCollection GetProperties(Attribute[] attributes)  
  90.           
  91.             PropertyDescriptor[] newProps = new PropertyDescriptor[this.Count];  
  92.             for (int i = 0; i < this.Count; i++)  
  93.               
  94.                 Property prop = (Property)this[i];  
  95.                 newProps[i] = new CustomPropertyDescriptor(ref prop, attributes);  
  96.               
  97.             return new PropertyDescriptorCollection(newProps);  
  98.           
  99.         public PropertyDescriptorCollection GetProperties()  
  100.           
  101.             return TypeDescriptor.GetProperties(thistrue);  
  102.           
  103.         public object GetPropertyOwner(PropertyDescriptor pd)  
  104.           
  105.             return this;          
  106.           
  107.         #endregion  
  108.       
  109. //属性类  
  110.     public class Property  
  111.       
  112.         private string _name=string.Empty;  
  113.         private object _value=null;  
  114.         private bool _readonly=false;  
  115.         private bool _visible=true;  
  116.         private string _category=string.Empty;  
  117.         TypeConverter _converter=null;  
  118.         object _editor = null;  
  119.         private string _displayname = string.Empty;  
  120.         public Property(string sName, object sValue)  
  121.           
  122.             this._name = sName;  
  123.             this._value = sValue;  
  124.           
  125.         public Property(string sName, object sValue, bool sReadonly, bool sVisible)  
  126.           
  127.             this._name = sName;  
  128.             this._value = sValue;  
  129.             this._readonly = sReadonly;  
  130.             this._visible = sVisible;  
  131.           
  132.         public string Name  //获得属性名  
  133.           
  134.             get  
  135.               
  136.                 return _name;  
  137.               
  138.             set  
  139.               
  140.                 _name=value;  
  141.               
  142.           
  143.         public string DisplayName   //属性显示名称  
  144.           
  145.             get  
  146.               
  147.                 return _displayname;  
  148.               
  149.             set  
  150.               
  151.                 _displayname = value;  
  152.               
  153.           
  154.         public TypeConverter Converter  //类型转换器,我们在制作下拉列表时需要用到  
  155.           
  156.             get   
  157.               
  158.                 return _converter;  
  159.               
  160.             set  
  161.               
  162.                 _converter = value;  
  163.               
  164.           
  165.         public string Category  //属性所属类别  
  166.           
  167.             get  
  168.               
  169.                 return _category;  
  170.               
  171.             set  
  172.               
  173.                 _category = value;  
  174.               
  175.           
  176.         public object Value  //属性值  
  177.           
  178.             get  
  179.               
  180.                 return _value;  
  181.               
  182.             set  
  183.               
  184.                 _value=value;  
  185.               
  186.           
  187.         public bool ReadOnly  //是否为只读属性  
  188.           
  189.             get  
  190.               
  191.                 return _readonly;  
  192.               
  193.             set  
  194.               
  195.                 _readonly = value;  
  196.               
  197.           
  198.         public bool Visible  //是否可见  
  199.           
  200.             get  
  201.               
  202.                 return _visible;  
  203.               
  204.             set  
  205.               
  206.                 _visible = value;  
  207.               
  208.           
  209.         public virtual object Editor   //属性编辑器  
  210.           
  211.             get   
  212.                
  213.                 return _editor;   
  214.               
  215.             set   
  216.                
  217.                 _editor = value;   
  218.               
  219.           
  220.       
  221.     public class CustomPropertyDescriptor : PropertyDescriptor  
  222.       
  223.         Property m_Property;  
  224.         public CustomPropertyDescriptor(ref Property myProperty, Attribute[] attrs)  
  225.             : base(myProperty.Name, attrs)  
  226.           
  227.             m_Property = myProperty;  
  228.           
  229.         #region PropertyDescriptor 重写方法  
  230.         public override bool CanResetValue(object component)  
  231.           
  232.             return false;  
  233.           
  234.         public override Type ComponentType  
  235.           
  236.             get  
  237.               
  238.                 return null;  
  239.               
  240.           
  241.         public override object GetValue(object component)  
  242.           
  243.             return m_Property.Value;  
  244.           
  245.         public override string Description  
  246.           
  247.             get  
  248.               
  249.                 return m_Property.Name;  
  250.               
  251.           
  252.         public override string Category  
  253.           
  254.             get  
  255.               
  256.                 return m_Property.Category;  
  257.               
  258.           
  259.         public override string DisplayName  
  260.           
  261.             get  
  262.               
  263.                 return m_Property.DisplayName!=""?m_Property.DisplayName:m_Property.Name;  
  264.               
  265.           
  266.         public override bool IsReadOnly  
  267.           
  268.             get  
  269.               
  270.                 return m_Property.ReadOnly;  
  271.               
  272.           
  273.         public override void ResetValue(object component)  
  274.           
  275.             //Have to implement  
  276.           
  277.         public override bool ShouldSerializeValue(object component)  
  278.           
  279.             return false;  
  280.           
  281.         public override void SetValue(object component, object value)  
  282.           
  283.             m_Property.Value = value;  
  284.           
  285.         public override TypeConverter Converter  
  286.           
  287.             get  
  288.               
  289.                 return m_Property.Converter;  
  290.               
  291.           
  292.         public override Type PropertyType  
  293.           
  294.             get  return m_Property.Value.GetType();   
  295.           
  296.         public override object GetEditor(Type editorBaseType)  
  297.           
  298.             return m_Property.Editor==nullbase.GetEditor(editorBaseType):m_Property.Editor;  
  299.           
  300.         #endregion  
  301.     </span>  
 public class PropertyManageCls : CollectionBase, ICustomTypeDescriptor
    
        public void Add(Property value)
        
            int flag=-1;
            if (value != null)
            
                if (base.List.Count>0)
                
                    IList <Property> mList=new List<Property>();
                    for (int i = 0; i < base.List.Count; i++)
                    
                        Property p = base.List[i] as Property;
                        if (value.Name == p.Name)
                        
                            flag = i;
                        
                        mList.Add(p);
                    
                    if (flag == -1)
                    
                        mList.Add(value);
                    
                    base.List.Clear();
                    foreach (Property p in mList)
                    
                        base.List.Add(p);
                    
                
                else
                
                    base.List.Add(value);
                
            
        
        public void Remove(Property value)
        
            if(value!=null&&base.List.Count>0)
            base.List.Remove(value);
        
        public Property this[int index]
        
            get
            
                return (Property)base.List[index];
            
            set
            
                base.List[index] = (Property)value;
            
        
        #region ICustomTypeDescriptor 成员
        public AttributeCollection GetAttributes()
        
            return TypeDescriptor.GetAttributes(this,true);
        
        public string GetClassName()
        
            return TypeDescriptor.GetClassName(this, true);
        
        public string GetComponentName()
        
            return TypeDescriptor.GetComponentName(this, true);
        
        public TypeConverter GetConverter()
        
            return TypeDescriptor.GetConverter(this, true);
        
        public EventDescriptor GetDefaultEvent()
        
            return TypeDescriptor.GetDefaultEvent(this, true);
        
        public PropertyDescriptor GetDefaultProperty()
        
            return TypeDescriptor.GetDefaultProperty(this, true);
        
        public object GetEditor(Type editorBaseType)
        
            return TypeDescriptor.GetEditor(this, editorBaseType, true);
        
        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        
            return TypeDescriptor.GetEvents(this, attributes, true);
        
        public EventDescriptorCollection GetEvents()
        
            return TypeDescriptor.GetEvents(this,true);
        
        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        
            PropertyDescriptor[] newProps = new PropertyDescriptor[this.Count];
            for (int i = 0; i < this.Count; i++)
            
                Property prop = (Property)this[i];
                newProps[i] = new CustomPropertyDescriptor(ref prop, attributes);
            
            return new PropertyDescriptorCollection(newProps);
        
        public PropertyDescriptorCollection GetProperties()
        
            return TypeDescriptor.GetProperties(this, true);
        
        public object GetPropertyOwner(PropertyDescriptor pd)
        
            return this;        
        
        #endregion
    
//属性类
    public class Property
    
        private string _name=string.Empty;
        private object _value=null;
        private bool _readonly=false;
        private bool _visible=true;
        private string _category=string.Empty;
        TypeConverter _converter=null;
        object _editor = null;
        private string _displayname = string.Empty;
        public Property(string sName, object sValue)
        
            this._name = sName;
            this._value = sValue;
        
        public Property(string sName, object sValue, bool sReadonly, bool sVisible)
        
            this._name = sName;
            this._value = sValue;
            this._readonly = sReadonly;
            this._visible = sVisible;
        
        public string Name  //获得属性名
        
            get
            
                return _name;
            
            set
            
                _name=value;
            
        
        public string DisplayName   //属性显示名称
        
            get
            
                return _displayname;
            
            set
            
                _displayname = value;
            
        
        public TypeConverter Converter  //类型转换器,我们在制作下拉列表时需要用到
        
            get 
            
                return _converter;
            
            set
            
                _converter = value;
            
        
        public string Category  //属性所属类别
        
            get
            
                return _category;
            
            set
            
                _category = value;
            
        
        public object Value  //属性值
        
            get
            
                return _value;
            
            set
            
                _value=value;
            
        
        public bool ReadOnly  //是否为只读属性
        
            get
            
                return _readonly;
            
            set
            
                _readonly = value;
            
        
        public bool Visible  //是否可见
        
            get
            
                return _visible;
            
            set
            
                _visible = value;
            
        
        public virtual object Editor   //属性编辑器
        
            get 
             
                return _editor; 
            
            set 
             
                _editor = value; 
            
        
    
    public class CustomPropertyDescriptor : PropertyDescriptor
    
        Property m_Property;
        public CustomPropertyDescriptor(ref Property myProperty, Attribute[] attrs)
            : base(myProperty.Name, attrs)
        
            m_Property = myProperty;
        
        #region PropertyDescriptor 重写方法
        public override bool CanResetValue(object component)
        
            return false;
        
        public override Type ComponentType
        
            get
            
                return null;
            
        
        public override object GetValue(object component)
        
            return m_Property.Value;
        
        public override string Description
        
            get
            
                return m_Property.Name;
            
        
        public override string Category
        
            get
            
                return m_Property.Category;
            
        
        public override string DisplayName
        
            get
            
                return m_Property.DisplayName!=""?m_Property.DisplayName:m_Property.Name;
            
        
        public override bool IsReadOnly
        
            get
            
                return m_Property.ReadOnly;
            
        
        public override void ResetValue(object component)
        
            //Have to implement
        
        public override bool ShouldSerializeValue(object component)
        
            return false;
        
        public override void SetValue(object component, object value)
        
            m_Property.Value = value;
        
        public override TypeConverter Converter
        
            get
            
                return m_Property.Converter;
            
        
        public override Type PropertyType
        
            get  return m_Property.Value.GetType(); 
        
        public override object GetEditor(Type editorBaseType)
        
            return m_Property.Editor==null? base.GetEditor(editorBaseType):m_Property.Editor;
        
        #endregion
    

下面我们来看看该如何使用,我们仍然在Form_load中添加代码如下:

[csharp] view plain copy print ?
  1. <span style="font-size: 13px;">            PropertyManageCls pmc = new PropertyManageCls();  
  2.             Property pp = new Property("ID""1"falsetrue);  
  3.             pp.Category = "基本信息";  
  4.             pp.DisplayName = "我的ID";  
  5.             pmc.Add(pp);  
  6.             propertyGrid1.SelectObject=pmc;</span>  
            PropertyManageCls pmc = new PropertyManageCls();
            Property pp = new Property("ID", "1", false, true);
            pp.Category = "基本信息";
            pp.DisplayName = "我的ID";
            pmc.Add(pp);
            propertyGrid1.SelectObject=pmc;
显示结果:


我们可以看到上面的属性显示很简单,如果想要自定义一个下拉框,或者有一个路径选择的该怎么办呢。

1)类型转换器

要实现下拉框的方法:使用类型转换器,需要继承与TypeConverter或者StringConverter,然后重写方法,代码如下:

[csharp] view plain copy print ?
  1. <span style="font-size: 13px;">    //下拉框类型转换器  
  2.     public class DropDownListConverter : StringConverter  
  3.       
  4.         object[] m_Objects;  
  5.         public DropDownListConverter(object[] objects)  
  6.           
  7.             m_Objects = objects;  
  8.           
  9.         public override bool GetStandardValuesSupported(ITypeDescriptorContext context)  
  10.           
  11.             return true;  
  12.           
  13.         public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)  
  14.           
  15.             return true;</span><span style='color: rgb(0, 130, 0); line-height: 15.39px; font-family: Consolas, "Bitstream Vera Sans Mono", "Courier New", Courier, monospace; font-size: 14px;'>//true下拉框不可编辑</span><span style="font-size: 13px;">  
  16. </span><span style="font-size: 13px;">  
  17.           
  18.         public override  
  19.         System.ComponentModel.TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)  
  20.           
  21.             return new StandardValuesCollection(m_Objects);//我们可以直接在内部定义一个数组,但并不建议这样做,这样对于下拉框的灵活             //性有很大影响  
  22.           
  23.     </span>  
    //下拉框类型转换器
    public class DropDownListConverter : StringConverter
    
        object[] m_Objects;
        public DropDownListConverter(object[] objects)
        
            m_Objects = objects;
        
        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        
            return true;
        
        public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
        
            return true;//true下拉框不可编辑

        
        public override
        System.ComponentModel.TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        
            return new StandardValuesCollection(m_Objects);//我们可以直接在内部定义一个数组,但并不建议这样做,这样对于下拉框的灵活             //性有很大影响
        
    

我们实现了下拉框类型转换器,但该如何使用呢?

使用方法一:我们仍然以Station类作为例子,在属性上方添加标记[TypeConverter(typeof(DropDownListConverter))],但在这种情况下,我们需要预先在DropDownListConverter中定义下拉框内容。

使用方法二:这种方法我们可以在外部定义数组,使用方便,使用方法代码如下:

[csharp] view plain copy C#自定义PropertyGrid属性

C# 如何定义让PropertyGrid控件显示[...]按钮,并且点击后以下拉框形式显示自定义控件编辑属性值

C# 自定义PropertyGrid中显示控件的大小,要求限定PropertyGrid中大小的值。

PropertyGrid:仅为特定属性删除自定义数据类型的属性

C# PropertyGrid 简单使用

自定义类在PropertyGrid上的展示方法