PropertyGrid控件就是Visual Studio开发工具里面的属性浏览器,我们在VS里面可以通过属性浏览器查看,修改控件的属性,并主要通过使用反射来检索项目的属性。
一.如何显示属性
1)普通显示
在PropertyGrid中显示属性很容易,我们可以直接给propertyGrid1.SelectedObject属性赋值,SelectObject属性可以获取或设置当前选定的对象,数据类型为object,这就意味着我们可以直接将一个对象赋给它。针对一个对象,它会将对象中的所有公共属性显示在PropertyGrid上。假如我们定义一个Station类,如下
- 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中代码如下
- private
void Form1_Load(object sender, EventArgs e) - {
-
Station s=new Station(); -
propertygrid1.SelectObject=s; - }
我们看到属性名显示都是英文,那样很不方便阅读如果我们像显示中文,该如何实现呢?
更改了显示方式
要更改某些属性的显示方式,您可以对这些属性应用不同的特性。特性是用于为类型、字段、方法和属性等编程元素添加批注的声明标记,在运行时可以使用反射对其进行检索。下面列出了其中的一部分:
DescriptionAttribute
BrowsableAttribute
ReadOnlyAttribute
DefaultValueAttribute
DefaultPropertyAttribute
下面我们在Station类中的属性Lon上方添加[CategoryAttribute("坐标"),DisplayNameAttribute("经度")],效果如下:
如果想要在属性表中添加颜色选择和字体选择那是很容易一件事,可以在Station类中添加Color类型属性,和Font类型属性,绑定后,就可以进行颜色选择和字体选择了,代码在Station中已经实现。
2)自定义显示
我们可以看出这种上面这种显示属性方法并不够灵活,我们不能方便的及时增加或者删除属性。
- "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 mList=new List(); -
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 EventDescriptorCollectio n GetEvents(Attribute[] attributes) -
{ -
return TypeDescriptor.GetEvents(this, attributes, true); -
} -
public EventDescriptorCollectio n GetEvents() -
{ -
return TypeDescriptor.GetEvents(this,true); -
} -
public PropertyDescriptorCollec tion 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 PropertyDescriptorCollec tion(newProps); -
} -
public PropertyDescriptorCollec tion 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中添加代码如下:
- "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;
我们可以看到上面的属性显示很简单,如果想要自定义一个下拉框,或者有一个路径选择的该怎么办呢。
1)类型转换器
要实现下拉框的方法:使用类型转换器,需要继承与TypeConverter或者StringConverter,然后重写方法,代码如下:
- "FONT-SIZE:
13px"> //下拉框类型转换器 -
public class DropDownListConverter : StringConverter -
{ -
object[] m_Objects; -
public DropDownListConverter(object[] objects) -
{ -
m_Objects = objects; -
} -
public override bool GetStandardValuesSupport ed(ITypeDescriptorContext context) -
{ -
return true; -
} -
public override bool GetStandardValuesExclusi ve(ITypeDescriptorContext context) -
{ -
return true;"LINE-HEIGHT: 15.39px; FONT-FAMILY: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace; COLOR: rgb(0,130,0); FONT-SIZE: 14px">//true下拉框不可编辑 - "FONT-SIZE:
13px"> -
} -
public override -
System.ComponentModel.TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) -
{ -
return new StandardValuesCollection (m_Objects);//我们可以直接在内部定义一个数组,但并不建议这样做,这样对于下拉框的灵活 //性有很大影响 -
} -
}
我们实现了下拉框类型转换器,但该如何使用呢?
使用方法一:我们仍然以Station类作为例子,在属性上方添加标记[TypeConverter(typeof(DropDownListConverter))],但在这种情况下,我们需要预先在DropDownListConverter中定义下拉框内容。
使用方法二:这种方法我们可以在外部定义数组,使用方便,使用方法代码如下:
- "FONT-FAMILY:
Arial; COLOR: #333333">"FONT-SIZE: 13px"> private void Form_load(object sender, EventArgs e) -
{ -
PropertyManageCls pmc = new PropertyManageCls(); -
string []s=new string[] { "1", "2", "3", "4" }; -
Property pp = new Property(txtname.Text,txtvalue.Text, false, true); -
pp.Category = "基本信息"; -
pp.DisplayName = "我的ID"; -
pp.Converter = new DropDownListConverter(s);//Property的Converter属性就可以设置类型转换 -
pmc.Add(pp); -
propertyGrid1.SelectObject = pmc; -
}
2)属性编辑器
使用属性编辑器实现路径选择:属性编辑器需要继承与UITypeEditor
- "FONT-SIZE:
13px">//文件路径选择 public class PropertyGridFileItem : UITypeEditor -
{ -
-
public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context) -
{ -
-
return UITypeEditorEditStyle.Modal; -
-
} -
-
public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System. -
- IServiceProvider
provider, object value) -
{ -
-
IWindowsFormsEditorServi ce edSvc = -
(IWindowsFormsEditorServi ce)provider.GetService(typeof(IWindowsFormsEditorServi ce)); -
-
if (edSvc != null) -
{ -
-
// 可以打开任何特定的对话框 -
-
OpenFileDialog dialog = new OpenFileDialog(); -
-
dialog.AddExtension = false; -
-
if (dialog.ShowDialog().Equals(DialogResult.OK)) -
{ -
-
return dialog.FileName; -
-
} -
} -
-
return value; -
-
} -
-
}
使用方法一:以Station类为例,在属性上方添加标记[EditorAttribute(typeof(PropertyGridFileItem),
使用方法二:使用方法代码如下:
- "FONT-SIZE:
13px"> private void Form_load(object sender, EventArgs e) -
{ -
PropertyManageCls pmc = new PropertyManageCls(); -
Property pp = new Property(txtname.Text,txtvalue.Text, false, true); -
pp.Category = "基本信息"; -
pp.DisplayName = "我的ID"; -
pp.Editor= new PropertyGridFileItem();//Property的Editor属性就可以设置属性编辑 -
pmc.Add(pp); -
propertyGrid1.SelectObject = pmc; -
}