c#怎样做到一改动propertygrid中的属性,就可以立即更新与他绑定的类的相应属性
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c#怎样做到一改动propertygrid中的属性,就可以立即更新与他绑定的类的相应属性相关的知识,希望对你有一定的参考价值。
就是数据绑定嘛。将类的属性绑定到propertygrid的属性上。使用Binding 参考技术A 从新加载一下,绑定的数据就会刷新C#自定义PropertyGrid属性
最近用到了PropertyGrid,原来从来没用到过,拿在手里,一头雾水,经过一段时间研究后,大概理解了Property的使用方法,下面仔细剖析一下。
PropertyGrid控件就是Visual Studio开发工具里面的属性浏览器,我们在VS里面可以通过属性浏览器查看,修改控件的属性,并主要通过使用反射来检索项目的属性。
一.如何显示属性
1)普通显示
在PropertyGrid中显示属性很容易,我们可以直接给propertyGrid1.SelectedObject属性赋值,SelectObject属性可以获取或设置当前选定的对象,数据类型为object,这就意味着我们可以直接将一个对象赋给它。针对一个对象,它会将对象中的所有公共属性显示在PropertyGrid上。假如我们定义一个Station类,如下
[csharp] view plain copy print ?
- 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;
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 ?
- private void Form1_Load(object sender, EventArgs e)
- Station s=new Station();
- propertygrid1.SelectObject=s;
private void Form1_Load(object sender, EventArgs e)
Station s=new Station();
propertygrid1.SelectObject=s;
我们就可以看到如下效果:
我们看到属性名显示都是英文,那样很不方便阅读如果我们像显示中文,该如何实现呢?
更改了显示方式
要更改某些属性的显示方式,您可以对这些属性应用不同的特性。特性是用于为类型、字段、方法和属性等编程元素添加批注的声明标记,在运行时可以使用反射对其进行检索。下面列出了其中的一部分:
DescriptionAttribute - 设置显示在属性下方说明帮助窗格中的属性文本。这是一种为活动属性(即具有焦点的属性)提供帮助文本的有效方法。
BrowsableAttribute – 表示是否在网格中显示属性。此特性可用于在网格中隐藏属性。默认情况下,公共属性始终显示在网格中。
ReadOnlyAttribute – 表示属性是否为只读。此特性可用于禁止在网格中编辑属性。默认情况下,带有 get 和 set 访问函数的公共属性在网格中是可以编辑的。
DefaultValueAttribute – 表示属性的默认值。如果希望为属性提供默认值,然后确定该属性值是否与默认值相同,则可使用此特性。可以将此特性应用于所有属性。
DefaultPropertyAttribute – 表示类的默认属性。在网格中选择某个类时,将首先突出显示该类的默认属性。
下面我们在Station类中的属性Lon上方添加[CategoryAttribute("坐标"),DisplayNameAttribute("经度")],效果如下:
如果想要在属性表中添加颜色选择和字体选择那是很容易一件事,可以在Station类中添加Color类型属性,和Font类型属性,绑定后,就可以进行颜色选择和字体选择了,代码在Station中已经实现。
2)自定义显示
我们可以看出这种上面这种显示属性方法并不够灵活,我们不能方便的及时增加或者删除属性。
//属性表管理类
[csharp] view plain copy print ?
- <span style="font-size: 13px;"> 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
- </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 ?
- <span style="font-size: 13px;"> PropertyManageCls pmc = new PropertyManageCls();
- Property pp = new Property("ID", "1", false, true);
- pp.Category = "基本信息";
- pp.DisplayName = "我的ID";
- pmc.Add(pp);
- 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 ?
- <span style="font-size: 13px;"> //下拉框类型转换器
- 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;</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;">
- </span><span style="font-size: 13px;">
- public override
- System.ComponentModel.TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
- return new StandardValuesCollection(m_Objects);//我们可以直接在内部定义一个数组,但并不建议这样做,这样对于下拉框的灵活 //性有很大影响
- </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),如何动态添加下拉框中的值。例如:Name : 下拉框中的值:小米,小明。
C#:更新时 PropertyGrid 不调用属性`Get`方法