运行时自定义PropertyGrid显示属性项目

运行时自定义PropertyGrid显示属性项目 简述

在PropertyGrid所显示的属性内容包括属性分类(Category)及组件属性,

在一般情况下直接使用PropertyGrid来显示一个对象的所有属性是非常方便的,只需一个语句就能完成:

propertyGrid.SelectedObject = component;

但在实际应用中可能会不需要显示所有属性项目,而是通过外部指定(通过XML等进行描述),这些设置一般情况下在创建组件时用代码中的Attribute来进行具体设置,如所属分类,显示标题等,这只能针对于一些自建的组件可以这么做。

问题描述

像上面所说,在创建自建组件时可以用Attribute的方式来设置PropertyGrid的显示样式,但这种方法不能应用于已有的组件,像系统中的TextBox,Button等,除非自己建立一个由这些组件派生的类,当然这样做会加大复杂度。像要实现下面所显示的这种效果在实际操作时会很麻烦。

左图是TextBox原有的所有属性,右图是经过处理后的属性

解决方法

在.Net中提供了一个自定义类型说明的接口(System.ComponentModel.ICustomTypeDescriptor),PropertyGrid可以直接自动处理用此接口生成的对象,因此在处理这个问题的时候只需要创建一个基于这个接口的处理类就可以达到世期望的目标,在这个接口中提供了GetProperties方法用于返回所选组件的所有属性,因此我们可以通过这个方法可以对我们所需要的属性进行过滤,下面是一段GetPropertys的处理代码:

 public PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
 { 
 List<CustomPropertyDescriptor> tmpPDCLst = new List<CustomPropertyDescriptor>(); 
 PropertyDescriptorCollection tmpPDC = TypeDescriptor.GetProperties(mCurrentSelectObject, attributes); 
 IEnumerator tmpIe = tmpPDC.GetEnumerator(); 
  CustomPropertyDescriptor tmpCPD; 
 PropertyDescriptor tmpPD; 
 while (tmpIe.MoveNext()) 
 { 
 tmpPD = tmpIe.Current as PropertyDescriptor; 
 if (mObjectAttribs.ContainsKey(tmpPD.Name)) 
 { 
 tmpCPD = new CustomPropertyDescriptor(mCurrentSelectObject, tmpPD); 
 tmpCPD.SetDisplayName(mObjectAttribs[tmpPD.Name]); 
          //此处用于处理属性分类的名称,可以在XML等设置文件中进行设置,在这段代码中只是简单的在分类后加了“中文”两个字 
 tmpCPD.SetCategory(tmpPD.Category + "中文"); 
 tmpPDCLst.Add(tmpCPD); 
  } 
 } 
 return new PropertyDescriptorCollection(tmpPDCLst.ToArray()); 
 } 

当然在进行属性过虑之后,PropertyGrid中所显示的属性名称都还是原有名称,若想同时改变在PropertyGrid中显示出来的名称则需要重写PropertyDescriptor中的部分方法,在上面这段代码中的CustomPropertyDescriptor就是一个基于PropertyDescriptor的类。 
在CustomPropertyDescriptor类中最主要的是重写DisplayName与Category这两个属性,但由于在PropertyDescriptor中这两个属性是只读的,因此在这个类中需要加入两个用于设置这两个属性的方法(或直接用Field)在这里我使用了SetDispalyName与SetCategory这两个方法: 

 private string mCategory; 
 public override string Category 
 { 
 get { return mCategory; } 
 } 
 private string mDisplayName ; 
 public override string DisplayName 
 { 
 get { return mDisplayName; } 
 } 
 public void SetDisplayName(string pDispalyName) 
 { 
 mDisplayName = pDispalyName; 
  } 
 public void SetCategory(string pCategory) 
 { 
 mCategory = pCategory; 
 } 
  就这样的几步,便可以将PropertyGrid中显示的内容完全自定义。 
在写ICustomTypeDescriptor接口时,其他的一些方法可以用TypeDescriptor直接返回相关方法调用,并在GetPropertyOwner方法中应返回当前选择对象否则将不会对修改值起任何作用 
 public object GetPropertyOwner(PropertyDescriptor pd) 
 { 
  return mCurrentSelectObject; 
 } 

在写CustomPropertyDescriptor类时需要一个PropertyDescriptor对象,在实现一些方法时直接返回这个对象的值。

当然也可以通过这个方法来自定义一些Events的输出, 使用方法 

//加载组件属性,从XML文件载入,此处为Button XmlNode tmpXNode = mXDoc.SelectSingleNode("Components/Component[@Name=\"Button\"]"); //选择属性设置 XmlNodeList tmpXPropLst = tmpXNode.SelectNodes("Propertys/Property"); //创建CustomProperty对象 CustomProperty cp = new CustomProperty(sender, tmpXPropLst); //设置PropertyGrid选择对象 propertyGrid1.SelectedObject = cp; 文件下载

源码

演示

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏跟着阿笨一起玩NET

C# Eval在aspx页面中的用法及作用

1972
来自专栏空帆船w

Android 编码规范

小驼峰命名(lowerCamelCase):除第一个单词以外,每一个单词的第一个字母大写。

1983
来自专栏iOSer成长记录

OpenGL ES(二) 三角形

1383
来自专栏JMCui

MongoDB系列一(查询).

一、简述     MongoDB中使用find来进行查询。查询就是返回一个集合中文档的子集,子集合的范围从0个文档到整个集合。默认情况下,"_id"这个键总是被...

4726
来自专栏Java帮帮-微信公众号-技术文章全总结

Java类加载器(用户自定义类加载器实现)

java类加载器主要分为如下几种: jvm提供的类加载器 根类加载器:底层实现,主要加载java核心类库(如:java.lang.*) 扩展类加载器:使用jav...

3536
来自专栏蓝天

struct对齐问题

741
来自专栏前端那些事

自制刻度尺插件-前端简易实现"腾讯信用"界面

依据我现有的知识,在前端上"简易"的实现了腾讯信用的界面,同时自己自制了一个竖直的刻度尺插件,曲线的位置可以根据传入的数值动态的改变,这次主要也想总结一下关于j...

27511
来自专栏林德熙的博客

WPF 开发

如果使用NamedPipeServerStream、Mutex做单实例,需要传入字符串,这时如果传入一个固定的字符串,会在多用户的时候无法使用。

1761
来自专栏前端说吧

【本周面试题】第2周 - 看上去和实际上的代码执行顺序

隐形考点,while小括号内部,会进行隐式转换,将其他类型的值转为Boolean布尔值类型的进行判断

862
来自专栏Java Web

初学Java Web(6)——JSP学习总结

为什么要学习 JSP Servlet 的短板: Servlet 的出现,是为了解决动态输出网页的问题。 虽然这样做目的能达到,但是存在一些缺陷: 在 Servl...

4357

扫码关注云+社区