ProperyGrid 的原理试探
在还没有详细学习ProperyGrid前,我对ProperyGrid的设想是这样的.
如果一个对象想在ProperyGrid中显示.应该实现供ProperyGrid访问的接口.
在这个接口中应该有类似于GetPropertys()这样的方法.
结构应该大概象下面这个图所示:
其中的Adaptor通过对MyClass的引用,负责设置所要显示的Properties,即实现IPropertySource中的GetPropertys方法.
这样的设计有一个优点,MyClass可以专注于自己的业务,不需要考虑如何显示自己.所有的UI部分将在Adaptor中完成.再通过我在以前的文章中介绍的Adaptor模式的应用,将使得Adaptor完全不为用户所知,.这样对用户来说应该很方便.
不过在随后的深入学习中发现, ProperyGrid并不是象我所想的这样.
ProperyGrid可以选择任意的对象.然后它就会把该对象的所有属性显示出来.如果是CLR内部支持的类型如string ,int它会显示的很好,如果不是,而是用户自定义的类型则需要用户自已做一些类型转换的工作.在这里不对此做详细介绍,相关内容可以查看msdn的一篇文章.
也就是如下面所示,至于PropertyGrid如何显示MyClass的属性 .net内部全帮你做了.
在此又不得不说ms的”傻瓜”战略.任何一个人都能够很方便的使用PropertyGrid,而不用掌握其中的原理.
在我的设计中通过一些技巧可以将MyClassPropertyAdaptor隐藏于用户,但IPropertySource还是存在的.而在.net中连这个接口都被隐藏了.
它是如何做到的呢?
由于没有源代码,我只能从我的理解谈谈,希望如果哪位高人了解能指点一二.
经过我的学习发现我一开始想到的IPropertySource这个接口在.net中还是存在的.不过改成了ICustomTypeDescriptor.
通过这个接口你可以自定义你所希望显示的对象属性.以及属性的名字(DisplayName)和描述(Description).
说到这里, 对于那些只知道用propertyGrid.SelectedObject=XXXObject的ms的”傻瓜”战略的受益者们,就有意义了. 为什么简单不好?我不知道原理不也把PropertyGrid用的好好的嘛.
如果你想让某些属性显示,某些不显示怎么办? 呵呵知道你可以用BrowseableAttribute.但是如果你要改变属性显示的名称怎么办?更为甚者你要显示一个数组怎么办?难道让每项属性名显示为[0],[1]…?
某些时候我们是需要定制所以显示的属性的,这个时候ICustomTypeDescriptor就派上用场了.
你只要让你的对象实现 ICustomTypeDescriptor接口中的GetProperties方法.
对于那些需要定制的属性让它继承PropertyDescriptor,然后override其中的方法,如(DisplayName,Description.) 而那些你不想改变的属性就原封不动的通过TypeDescriptor.GetProperties(typeof(XXXObject))["xxxProperty"]填到Properties列表中就可以.
既然在.net中也找到了这么一个接口,我就猜想.net中的PropertyGrid的实现原理是不是这样?
先检查propertyGrid.SelectedObject是否实现了ICustomTypeDescriptor接口.如果有,就通过这个 接口获得显示所需要的属性.如果没有就自动为所选中的对象做一个Adaptor,然后让这个Adaptor实现ICustomTypeDescriptor接口, GetProperties方法采用默认实现即获得该对象的所有的属性.
也不知道猜的对不对.
最后提醒大家一下: 当你想让你的对象在PropertyGrid中显示的时候, 最好对它做一个Adaptor. 因为你可能想设置一些属性在PropertyGrid中显示时的特性,比如利用[Category]设置它的分类.这些涉及UI的操作最好不要出现在原来的业务对象中.