DotNet(C#)自定义运行时窗体设计器Runtime FormDesigner(转载)
写在前面:因为业务的需要,有时会使用到自定义运行时窗体设计器Runtime FormDesigner,实现的功能,就是IDE设计器的简化。设想一下,如果可以在程序运行时,再设计一个Form,然后编译代码,那是多么强大呀。下面介绍几个重要的Runtime FormDesigner,其中大部分来自了微软的官方网站或MSDN。
重要的链接资源
下面介绍有4个重要的Form设计器,它们是:
1,Designerhost
http://support.microsoft.com/?id=813808
INFO: 代码示例演示如何通过使用 VisualC # .NET 创建自定义窗体设计器
.Net1.1下运行的Form设计器
2,DesignerHosting
http://msdn.microsoft.com/msdnmag/issues/06/03/DesignerHosting/default.aspx
.Net2.0下运行的Form设计器
3,CustomFormsDesigner
http://download.microsoft.com/download/d/3/1/d31fff33-fd97-488f-9bbd-4b7402905716/CustomFormsDesigner.exe
.Net1.1下运行的Form设计器
4,Hosting
http://www.divil.co.uk/net/articles/designers/hosting.asp
来自divil.co.uk的Hosting
.Net2.0下运行的Form设计器
运行效果图
下面是1,DesignerHost就运行图,你是不是很震惊呢?反正,我第一眼看到这个运行时窗体设计器时,实在是太震惊了,一个只有20-30个源文件的项目,运行时,能够产生如此强大的界面,真是不敢相信,又万分喜悦,而其它三个FormDesigner也是产生相似的界面。这简直就是一个IDE系统,与VisualStudio2005一样啊,而且,它可以产生代码,可以产生C# Source,VB Source和XML。
功能介绍
工具的左边是工具箱,右边是属性设置窗口,中间是Form设计器,工具箱,跟平时使用的VisualStudio一样,多个选项卡,WindowsForms选项卡中有多个普通工具,有Components选项卡中有部件控件,而CustomControls选项卡中有用户自定义的控件,Datas选项卡中有系统的数据链接控件,如OleDbConnection之类,当然,也不仅仅是这些内容,你可以通过代码修改来增改左侧的控件。
往上一点看,有Design,C#Source,VB Source,XML四个视图的选择,Design是设计视图,指的就是当前看到的界面,C# Source,VB Source跟我们在IDE工具中使用查看源代码所得到的东西一样。而XML则是我们之前没有见到的。它用于描述当前的Form的内容,如Form的属性和值,布局,层次,Form中的控件等等。
菜单栏中,File下拉后,就是日常的保存,另保存,打开,退出等功能,而Edit就是编辑功能,如,复制,剪切,删除,对齐等,View就是视图界面,如Design,C#Source,VB Source,XML,Layout就是控件的层次移动等,Debug中,就是运行,编译等功能。
可以说上,这个控件是四个中做得比较好的。操作起来也方便。
精彩的文章还在继续,下一会,将介绍Runtime Form Designer的机制,编写,编译方法,请留意订阅首页的Rss
运行时窗体设计器Runtime Form Designer一出现,就会以其出色的表现,奇怪的代码吸引,怎么说是奇怪的代码呢?设计器所使用到的ImenuCommandService,InameCreationService,ItoolboxService,IUIService,IdesignerHost,IselectionService 这些接口,使用过没用?在设计一个运行时设计器时,忽然学得,自己是在学习一个新的语言,是使用.Net来表示的底层界面接口语言。简单而言,.Net已经帮助你写好了底层的底层,那就是编写设计的接口。你只要继承或重写代码,就可以实现设计器的功能。查看重要的Form设计器用这个网址:
http://www.myfirm.cn/News/DotNetUserInterface/20080221013104408.html
为了使用最简单的方式来说明问题,使用最简单的设计器来做说明,下面介绍Hosting
效果图
所有代码图
这个项目,相当的小,上面显示的就是所有的源文件,可以高兴地认为,只要学会了上面的类,就成功了。事实上,只要学会几个重要的类,就可以了。
重点研究的接口
在理解下面接口的时候,可以理解为,自己是微软的高级工程师,正在为VisualStudio开发工具箱,界面,界面,菜单等等界面功能。
IMenuCommandService
提供的方法用于管理设计模式下可用的全局设计器谓词和菜单命令,以及显示某些类型的快捷菜单。
简单说,就是新建的控件,在窗体Form中产生的命令,如移动,对齐,层次叠放,复制,剪切,粘贴
INameCreationService
提供可以生成对象的唯一名称的服务。
因为各个拖出来的控件都必须有唯一的名称,这样,才可以编译通过的。
IToolboxService
提供在开发环境下管理和查询工具箱的方法和属性。
这就是一个工具箱,一个同工具箱提供一样功能的服务。
IDesignerHost
提供用于管理设计器事务和组件的接口。
这是最重要的接口,所有的控件都是由这个接口发出,可以理解为,从这个接口可以找到所有控件的引用。
ISelectionService
为设计器提供用于选择组件的接口。
就是当程序运行时,在Form设计器选择控件时,产生的事件,它常常被用来更新属性窗口。
IUIService
启用与开发环境对象(正在承载设计器)的用户界面的交互。
PropertyGrid
这不是一个接口,这只是一个控件,不过,提供了属性设置服务,是用户交互最频繁的服务之一。
服务的加载
可以这样理解,运时时Form设计器,就是一个服务的集合,服务管理器ServiceContainer初始化之后,绑定DesignerHost,然后不断增加服务,如
InameCreationService,名字唯一服务
ItoolboxService,工具箱服务
ImenuCommandService,菜单命令服务
IselectionService,选择服务(同时产生选择变化事件,从而改变属性显示)
PropertyGrid,属性设置服务
最后,由DesignerHost做激活动作,host.Activate();
关于命令服务
在运行时设计器中,要删除选定的控件,只能使用命令接口提供的功能。如
menuService.GlobalInvoke(StandardCommands.Delete);
当然,一个很高明的做法是,一开始就将DesignerHost的所有可能的命令纳入线程的管理,在designerhost.exe,中有使用。你可以在上一篇介绍Runtime Form Designer的文章中,找到这个控件的链接。
下一篇,将介绍Runtime FormDesigner的运行和编译机制,不可错过。
之前已经有两篇文章对Form Designer运行了分析和展示,具体展示了几个重要的开源Form设计器,也介绍了最基本的Form设计器的编写方式。而在介绍Hosting设计器时,没有提及到代码的展示与编译运行机制,下面,本文就对运行时Form设计器的代码转换和编译机制进行分析和学习。下面介绍Designerhost工具。
界面效果图
代码的产生
将注意力投放到SampleDesignerLoader.cs类,上图中Design,C# Source,VB Source,XML视图的变化,都会产生事件,事件处理方法就是SampleDesignerLoader类的Flush方法,表示对当前控件与代码的刷新。
一个重要的类,类中的类
System.CodeDom.CodeCompileUnit
在.Net中,一个源文件,如C#写好的.cs文件,其实可以转化为一个类中类CodeCompileUnit,这个类中类有构造函数,方法体,属性,命名空间等等的定义。如引入System命名空间,你可以这样写Imports.Add(new CodeNamespaceImport("System")); CodeConstructor是用来定义构造函数的。可以说,一个类实体的定义,运行时本身就是一个CodeCompileUnit类的实例。类的序列化功能,就是由CodeCompileUnit发起的重要功能。
类的序列化可以将一个类变成一个文件如XML,而这个XML中记录了各个属性和值,在网络环境中,就可以作为一个传送的介质,这样,就可以实现类的远程调用。
重要的代码
RootDesignerSerializerAttribute a = TypeDescriptor.GetAttributes(root)[typeof(RootDesignerSerializerAttribute)] as RootDesignerSerializerAttribute;
Type t = host.GetType(a.SerializerTypeName);
CodeDomSerializer cds = Activator.CreateInstance(t) as CodeDomSerializer;
IDesignerSerializationManager manager = host.GetService(typeof(IDesignerSerializationManager)) as IDesignerSerializationManager;
CodeTypeDeclaration td = cds.Serialize(manager, root) as CodeTypeDeclaration;
在设计界面拖动的控件和设置的属性都通过对根设计器的序列化,被完全提取出来,成为一个CodeCompileUnit的主体部分。再增加构造函数和其它属性就可以了。
编译与生成
要编译的话,就必须传入数据CodeCompileUnit,然后使用CsharpCodeProvider,
VBCodeProvider就可以生成相应代码,也就是说,在设计的时候,不必要先指定使用何种语言,在设计完Form之后,再选定就可以了。因为,Form设计器最后产生的,是CodeCompileUnit,而不是代码。
在SampleDesignerLoader.cs类上,也提供了Build方法,这就是生成DLL或EXE文件,因为在Windows平台上,可以正常使用类集合的,就只要用这两个扩展名。只要使用CompilerParameters类和当前的程序类,传入CodeCompileUnit就可以了。之后,就只是生成选择了。详情请查看Build方法