PropertyGrid,.net框架下的一个控件,这是一个软件升级的项目,原来的软件用的是C++,控件用的还是第三方,这次升级到visual studio .net4.0版本,原以为.net的东西用起来不会费劲的,没想到想要实现项目需要的效果还真没那么简单。

由于需要,我这里主要是为了能动态的生成属性页,还要带能动态生成下来菜单,所以今天主要从这方面总结。

首先定义一个属性类:

//单条属性类

public class XProp { private string theId = ""; //属性Id,我的项目中需要,大家可以忽略

private string theCategory = ""; //属性所属类别

private string theName = ""; //属性名称

private bool theReadOnly = false; //属性的只读性,true为只读

private string theDescription = ""; //属性的描述内容

private object theValue = null; //值

private System.Type theType = null; //类型

private bool theBrowsable = true; //显示或隐藏,true为显示

TypeConverter theConverter = null; //类型转换

public string Id { get { return theId; }

set { theId = value; } }

public string Category { get { return theCategory; }

set { theCategory = value; } } public bool ReadOnly { get { return theReadOnly; }

set { theReadOnly = value; } } public string Name { get { return this.theName; }

set { this.theName = value; } } public object Value { get { return this.theValue; }

set { this.theValue = value; } } public string Description { get { return theDescription; }

set { theDescription = value; } }

public System.Type ProType { get { return theType; }

set { theType = value; } }

public bool Browsable { get { return theBrowsable; } set { theBrowsable = value; } }

public virtual TypeConverter Converter { get { return theConverter; } set { theConverter = value; } } }

我举一个例子: private string strdemo;

[DescriptionAttribute("用于举例说明"), CategoryAttribute("公有属性"), DefaultValueAttribute(“测试属性”), ReadOnlyAttribute(false), BrowsableAttribute(true), TypeConverter(typeof(MyComboTypeConvert)) ] public string strDemo { get { return strdemo; } set { strdemo = value; } }

这是个写死的属性,那在我的项目中,根据对象的不同,会需要生产不同的属性页,所以需要一个可以动态生成的属性页,将上述这个一般属性定义,利用XProp类,写成: Private XProp newXpro = new XProp(); newXpro.Category = ”公有属性”; newXpro.Name = ” strDemo”; newXpro.Id = "A"; newXpro.Description = “用于举例说明”; newXpro.ReadOnly =false; newXpro.Value = “测试属性”; newXpro.ProType = typeof(string); newXpro.Browsable = true; newXpro.Converter = null;

这样,一条属性就完成了。当然你也可以根据需要自己重写更多的属性相关定义。这里的Converter属性是在后面的下拉菜单中需要用到的,如果不是基础类型的(string,int,bool,enum等),我们可以赋值为null.

当然,这只是一条属性,原本按之前的方法,只要定义一个类,然后这个类里面定义多条属性就可以了。但是现在,由于属性是动态生成的,我们并不能确定需要几个属性,也就不能直接在一个类里面定义完。

所以我们需要再定义一个List<XProp>类,作为一一张list可以随意添加多个项,然后将PropertyGrid.SelectedObject设置为这个类就好了:

先来定义以下两个类:

public class XProps : List<XProp>, ICustomTypeDescriptor

{

#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(System.Type editorBaseType)

{

return TypeDescriptor.GetEditor(this, editorBaseType, true);

}

public EventDescriptorCollection GetEvents(System.Attribute[] attributes)

{

return TypeDescriptor.GetEvents(this, attributes, true);

}

public EventDescriptorCollection GetEvents()

{

return TypeDescriptor.GetEvents(this, true);

}

public PropertyDescriptorCollection GetProperties(System.Attribute[] attributes)

{

ArrayList props = new ArrayList();

for (int i = 0; i < this.Count; i++)

{ //判断属性是否显示

if (this[i].Browsable == true)

{

XPropDescriptor psd = new XPropDescriptor(this[i], attributes);

props.Add(psd);

}

}

PropertyDescriptor[] propArray = (PropertyDescriptor[])props.ToArray(typeof(PropertyDescriptor));

return new PropertyDescriptorCollection(propArray);

}

public PropertyDescriptorCollection GetProperties()

{

return TypeDescriptor.GetProperties(this, true);

}

public object GetPropertyOwner(PropertyDescriptor pd)

{

return this;

}

#endregion

public override string ToString()

{

StringBuilder sb = new StringBuilder();

for (int i = 0; i < this.Count; i++)

{

sb.Append("[" + i + "] " + this[i].ToString() + System.Environment.NewLine);

}

return sb.ToString();

}

}

private class XPropDescriptor : PropertyDescriptor

{

XProp theProp;

public XPropDescriptor(XProp prop, Attribute[] attrs): base(prop.Name, attrs)

{

theProp = prop;

}

public override bool CanResetValue(object component)

{

return false;

}

public override string Category

{

get { return theProp.Category; }

}

public override string Description

{

get { return theProp.Description; }

}

public override TypeConverter Converter

{

get { return theProp.Converter; }

}

public override System.Type ComponentType

{

get { return this.GetType(); }

}

public override object GetValue(object component)

{

return theProp.Value;

}

public override bool IsReadOnly

{

get { return theProp.ReadOnly; }

}

public override System.Type PropertyType

{

get { return theProp.ProType; }

}

public override void ResetValue(object component)

{

}

public override void SetValue(object component, object value)

{

theProp.Value = value;

}

public override bool ShouldSerializeValue(object component)

{

return false;

}

}

然后我们新声明一个属性列表: Private XProps xprops = new XProps(); 再将刚刚那个动态生成的属性添加进去,将属性页的selectobject赋值为这个类: xprops.add(newXpro); PropertyGridDemo.SelectedObject = xprops; 现在我们来看看效果:

根据需要,你可以添加多条属性。

也许你会想问,这里哪有动态生成啊,那些属性名称,属性类型什么的不还是写死的么。呵呵,我这里只是举个例子所以写死了,在实际应用中,你可以根据需要,在生成属性列表的时候,动态赋值,例如你是从xml文件里读取到的,例如你是从服务器中获取到的。根据你读取的对象,一个一个赋值就可以了。

下面来介绍如何在属性页中动态生成下拉菜单框,关于下拉菜单真的是很复杂,在.net的PropertyGrid控件中,想要具有下拉菜单的属性,简单的可以通过枚举类型来实现,还是以刚刚的那个例子来说明: 首先定义个枚举类型:

public enum enumType { BOOLVAL, DIGITALVAL, STRINGVAL, CHECKVAL, RATIOVAL, IPVAL, COMBOBOX, RESETBTN }

然后代码中将属性值与属性类型修改为: newXpro.Value = CustomClass.enumType.BOOLVAL; //这里的属性值当然必须为枚举中的某一项 newXpro.ProType = typeof(enumType); 然后我们来看看实现的效果:

这就是最简单的下拉菜单的实现方式了。 但是这里的枚举类型仍然是需要代码中写死的,而我在网上也所搜了很久,枚举类型似乎没办法动态生成,如果要实现动态生成恐怕要另寻他途。 所幸的是,我曾经见过重写combobox来生成属性页的下来菜单的,我们需要定义:

//重写下拉菜单中的项,使之与属性页的项关联 public abstract class ComboBoxItemTypeConvert : TypeConverter { public Hashtable myhash = null; public ComboBoxItemTypeConvert() { myhash = new Hashtable(); GetConvertHash(); } public abstract void GetConvertHash(); //是否支持选择列表的编辑 public override bool GetStandardValuesSupported(ITypeDescriptorContext context) { return true; } //重写combobox的选择列表 public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) { int[] ids = new int[myhash.Values.Count]; int i = 0; foreach (DictionaryEntry myDE in myhash) { ids[i++] = (int)(myDE.Key); } return new StandardValuesCollection(ids); } //判断转换器是否可以工作 public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { if (sourceType == typeof(string)) { return true; } return base.CanConvertFrom(context, sourceType);

} //重写转换器,将选项列表(即下拉菜单)中的值转换到该类型的值 public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object obj) { if (obj is string) { foreach (DictionaryEntry myDE in myhash) { if (myDE.Value.Equals((obj.ToString()))) return myDE.Key; } } return base.ConvertFrom(context, culture, obj); }

public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { if (destinationType == typeof(string)) { return true; } return base.CanConvertTo(context, destinationType);

}

//重写转换器将该类型的值转换到选择列表中 public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object obj, Type destinationType) {

if (destinationType == typeof(string)) { foreach (DictionaryEntry myDE in myhash) { if (myDE.Key.Equals(obj)) return myDE.Value.ToString(); } return ""; } return base.ConvertTo(context, culture, obj, destinationType); } public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) { return false; } } //重写下拉菜单,在这里实现定义下拉菜单内的项 public class MyComboItemConvert : ComboBoxItemTypeConvert { private Hashtable hash; public override void GetConvertHash() { try { myhash = hash; } catch { throw new NotImplementedException(); } } public MyComboItemConvert(string str) { hash = new Hashtable(); string[] stest = str.Split(','); for (int i = 0; i < stest.Length; i++) { hash.Add(i, stest[i]); } GetConvertHash(); value = 0; }

public int value { get; set; }

public MyComboItemConvert(string str,int s) { hash = new Hashtable(); string[] stest = str.Split(','); for (int i = 0; i < stest.Length; i++) { hash.Add(i, stest[i]); } GetConvertHash(); value = s; } }

在这里你可以看到,MyComboItemConvert有两个重载,分别有不同的参数,其中string类型的那个参数就是用于获取下拉菜单的项的。当然你也可以根据需要定义为其他类型的,例如List或是HashTable。只要在函数中将下拉菜单的每一项放入哈希表中就可以了。 而在生成的代码中,我们就需要用到刚刚没有使用的Converter属性了: 举个例子:

XProps xps = new XProps(); XProp xprop = new XProp(); xprop.Name = "姓名"; xprop.Value = "某人; xprop.Category = "人类"; xprop.Description = "姓甚名谁"; xprop.ProType = typeof(String); xprop.ReadOnly = true; xps.Add(xprop);

xprop = new XProp(); xprop.Category = "人类"; xprop.Name = "年龄"; xprop.ProType = typeof(int); xprop.Value = "2"; xprop.Description = "多大年纪"; xprop.ReadOnly = false; xps.Add(xprop);

xprop = new XProp(); xprop.Category = "人类"; xprop.Name = "性别"; xprop.Value = 1; xprop.ReadOnly = false; xprop.ProType = typeof(CustomClass.MyComboItemConvert); xprop.Converter = new CustomClass.MyComboItemConvert("M,F"); xprop.Description = "性别是男是女"; xps.Add(xprop);

xprop = new XProp(); xprop.Category = "人类"; xprop.ReadOnly = false; xprop.Name = "国籍"; xprop.Value = 1; xprop.ProType = typeof(CustomClass.MyComboItemConvert); xprop.Converter = new CustomClass.MyComboItemConvert("中,英,美,法"); xprop.Description = "国籍"; xps.Add(xprop);

PropertyGrideTest.SelectedObject = xps;

来看一下效果:

到这里,我需要的功能都能实现啦。

在这个过程中,我也在网上搜寻了很久,要感谢以下几篇博文,及其博主:

http://blog.csdn.net/luyifeiniu/article/details/5426960#创建 PropertyGrid 控件

http://blog.csdn.net/akron/article/details/2750566

http://www.cnblogs.com/greatverve/archive/2012/02/09/propertygird-bind.html

转载自http://blog.sina.com.cn/s/blog_6f14b7010101b91b.html

C# 属性控件2的更多相关文章

  1. 在C#中使用属性控件添加属性窗口

    转自原文 在C#中使用属性控件添加属性窗口 第一步,创建在应用程序中将要展现的字段属性为public公有属性.其中,所有的属性必须有get和set的方法(如果不设置get方法,则要显示的属性不会显示在 ...

  2. 属性控件CMFCPropertyGridCtrl简单用法

    这是我的原创! 用一堆的编辑框下拉框做配置界面,很是繁琐,还要对齐排版……用这个属性控件 CMFCPropertyGridCtrl 就可以统一风格了. //初始化 CMFCPropertyGridCt ...

  3. C# 属性控件的应用(备忘)

    自己定义的控件属性:[Browsable(true),Bindable(true),Category("数据"),DefaultValue(""),Locali ...

  4. Extjs 属性控件[转载]

    Ext.form.TimeField: 配置项:            maxValue:列表中允许的最大时间            maxText:当时间大于最大值时的错误提示信息          ...

  5. delphi控件属性大全-详解-简介

    http://blog.csdn.net/u011096030/article/details/18716713 button 组件: CAPTION 属性 :用于在按钮上显示文本内容 Cancel ...

  6. VB6 仿.netWinfrom控件 Anchor属性类

    vb6中控件没有anchor与dock属性,窗体变大后原来要在resize中调整控件的move属性,否则就面目全非了.网上找到一些调整控件大小的代码,发现并不太适合自己,于是按照思路自己做了一个类似a ...

  7. [转]Delphi 控件属性和事件

    常用[属性] Action:该属性是与组件关联的行为,允许应用程序集中响应用户命令 Anchors:与组件连接的窗体的位置点 Align:确定组件的对齐方式 AutoSize:确定组件是否自动调整其大 ...

  8. android 自己定义控件属性(TypedArray以及attrs解释)

    近期在捣鼓android 自己定义控件属性,学到了TypedArray以及attrs.在这当中看了一篇大神博客Android 深入理解Android中的自己定义属性.我就更加深入学习力一番.我就沿着这 ...

  9. Qt编写控件属性设计器4-加载属性

    一.前言 控件能加载拖曳拉伸了,这些都是基本的前提工作,接下来的重点就是要动态加载选中控件的属性了,Qt的属性机制那是异常的强大,只能用强大到爆来形容,Qt中编写自定义控件,如果属性都用Q_PROPE ...

随机推荐

  1. JAVA求集合中的组合

    好几个月没弄代码了,今天弄个求组合的DEMO 思路是将集合的每个值对照一个索引,索引大小是集合的大小+2.索引默认为[000...000],当组合后选取的组合值demo为[0100..00].然后根据 ...

  2. QT-4.8.6 编译配置过程

    1.编译 TSLib sudo apt-get install automake autogen libtool libtool-bin./autogen.sh./configure --host=a ...

  3. Linux Mint 17使用小结

    用过蛮多的linux系统 linux mint是我比较喜欢和常用的一个系统,装的是linux mint xfce 64位版本,在这里记录使用中遇到的一些问题及解决的方法,备忘,方便以后查看. 1.首先 ...

  4. BaseHttpListActivity,几行代码搞定Android Http列表请求、加载和缓存

    Android开发中,向服务器请求一个列表并显示是非常常见的需求,但实现起来比较麻烦,代码繁杂. 随着应用的更新迭代,这种需求越来越多,我渐渐发现了实现这种需求的代码的共同点. 于是我将Activit ...

  5. python cmd下运行中文乱码 策略

    如我运行一个脚本,执行后输出中文看不懂 然后呢在文件头加上 from __future__ import unicode_literals 注意:需要去掉所有字符串前的 u, 这样所有字符串均默认为u ...

  6. MD5使用

    MD5加密算法,即"Message-Digest Algorithm 5(信息-摘要算法)",它由MD2.MD3.MD4发展而来的一种单向函数算法(也就是HASH算法),它是国际著 ...

  7. C# dll加载,抽象方法的使用

    抽象类! dll的使用 /// <summary> /// 返回类型--插件 /// </summary> /// <param name="baseName& ...

  8. 修改加粗cmd和powershell命令行的中文字体

    powershell 传教士 原创文章 2016-06-20 允许转载,但必须保留名字和出处,否则追究法律责任 ---[前言]--- 1 环境: win10 10586 powershell 5.0 ...

  9. Tomcat批处理文件小结

    Tomcat批处理文件小结 一:嗯,如果你不了解Windows批处理文件,并且想了解一下,请先参看下面的链接资源(我也是因为想了解一下Windows批处理文件是用什么写的?怎么写的?才在园中找的,下面 ...

  10. VisualSVN 4.0.12补丁原创发布

    VisualSVN 4.0.12补丁原创发布