Multiple DesignSurfaces
当管理多个DesignSurfaces,一个好主意是使用DesignSurfaceManager。它使得容易管理这些DesignSurfaces(注意 DesignSurfaceManager 的服务也是可得的到 DesignSurface.)
调用DesignSurfaceManager.CreateDesignSurface将调用CreateDesignSurfaceCore,你能够重写这个函数去创建一个自定义的DesignSurface和增加服务。示例程序在类HostSurfaceManager通过重写这个函数创建了自定义的HostSurface:
protected override DesignSurface CreateDesignSurfaceCore(IServiceProvider parentProvider) { return new HostSurface(parentProvider); }
|
你能通过HostSurfaceManager类的事件ActiveDesignSurfaceChanged更新output窗口,代码如下:
void HostSurfaceManager_ActiveDesignSurfaceChanged(object sender, ActiveDesignSurfaceChangedEventArgs e) { ToolWindows.OutputWindow o = this.GetService(typeof(ToolWindows.OutputWindow)) as ToolWindows.OutputWindow; o.RichTextBox.Text += "New host added.\n"; |
DesignerLoaders 到现在为止我已经实现了DesignSurfaces、宿主设计器、添加控件、Toolbox和存取服务,像 OutputWindow. 下一个步骤要持久化设计器。设计器载入程序如同你将会期待一样, 负责从持久化介质加载Designer form. 设计器载入程序只有少许的需求. 事实上,你能创建Windows Forms designer的一个实例。
除了载入设计器,设计器载入程序对设计结果的保存也是设计器的职责。因为保存是可选择的行为,一个设计者载入程序侦听改变来自设计器的改变事件,而且自动的保存这些状态。.
.NET Framework 2.0引入两个新的类来自定义加载器:BasicDesignerLoader 和CodeDomDesignerLoader,示例应用举例说明两者的载入程序类型的实现。然而,如果你正在使用一个载入程序,它应该用来装载DesignSurface. 你将使用的 BeginLoad 代码片断当使用载入程序的时候应该看起来有点像下面的代码:
// Load it using a Loader ds.BeginLoad(new MyLoader()); |
DesignerLoader 负责载入 DesignSurface 的根组件而且创建任何组件. 当创造一个新的Form或任何其他的根组件的时候,载入程序只是装载它. 和从代码文件或一些其他的存储介质的载入,载入程序负责解析文件或者存储而且再创建根组件的任何其他的必需组件.
.NET Framework定义了一个抽象基类叫做DesignerLoader,用于加载和保存设计器到持久介质。基类是abstract,因此任何持久化模型都可以使用这个类,但是,这也增加了实现类的复杂性。
BasicDesignerLoader提供了除任何数据的持久格式外设计者载入程序的完全和通常的实现. 像 DesignerLoader ,它是abstract, 不处理关于持久化格式的任何事情. BasicDesignerLoader处理标准的工作:如何时该保存,知道该如何再装载, 而且追踪来自设计器的变化通知. 它的特征包括对多依赖加载,保存变化, 而且延期加载支持。
服务被 BasicDesignerLoader 添加到设计器的服务容器(service container)中。像其他的服务一样,你能够修改被保护的 LoaderHost 属性来修改可替换的服务。示例应用程序实现持久化XML格式的类是BasicDesignerLoader. 为了了解它如何工作,选择菜单 File | Type | BasicDesignerLoader.. 然后选择菜单File | New | Form创建一个新的Form,查看它所生成的XML文件,选择菜单View | Code | XML. 所看到的XML文件的内容类似于下面的内容:
<Object type="System.Windows.Forms.Form, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="Form1" children="Controls">
<Property name="Name">Form1</Property> <Property name="DataBindings"> <Property name="DefaultDataSourceUpdateMode">OnValidation</Property> </Property> <Property name="ClientSize">292, 273</Property> </Object> |
BasicDesignerLoader的PerformFlush 和 PerformLoad 是二个abstract方法是你为实现序列化和反序列化的功能必须实现的方法.
CodeDomDesignerLoader 设计时序列化是通过产生代码来实现,代码生成Schema的一个挑战是如何处理多语言。.NET Framework被设计为多语言协同工作,因此我也希望设计器能够生成多语言。有二个方法来达到解决这个问题. 第一要需要每个语言厂商为他们的语言写代码生成引擎. 不幸的是,没有语言厂商能够预期第三方组件厂商代码生成的多样性需求. 第二种方式要需要每个组件厂商提供代码生成器给他们支持的每种语言.因为被支持的语言的数量是未知的,所以这相当糟糕。
为了解决这个问题,.Net Framework定义了一个对象模型叫做代码文档对象模型(CodeDOM),所有的原始代码能本质上分解为原始的元素的组合,而且 CodeDOM 是那些元素的对象模型.当代码依附在CodeDOM, 生成的对象模型能够给不同语言的代码生成器生成适当的代码。
.NET Framework 2.0引入了CodeDomDesignerLoader类,继承自BasicDesignerLoader。CodeDomDesignerLoader是一个通过CodeDom进行读写支持的全功能的加载器。它是设计者加载器, 因而你所需要做全部的是CodeDomProvider.
示例应用中你可以选择菜单File | Type | CodeDomDesigner-Loader来看CodeDom的实做例子。创建新的Form通过菜单File | New | Form---这创建一个DesignSurface和用CodeDomDesignerLoader加载它。查看代码,通过选择菜单View | Code | C#查看Form生成的C#代码,或者选择菜单View | Code | VB查看Visual Basic代码。
CompilerParameters cp = new CompilerParameters();
AssemblyName[] assemblyNames = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
foreach (AssemblyName an in assemblyNames) { Assembly assembly = Assembly.Load(an); cp.ReferencedAssemblies.Add(assembly.Location); }
cp.GenerateExecutable = true; cp.OutputAssembly = executable;
cp.MainClass = "DesignerHostSample." + this.LoaderHost.RootComponent.Site.Name;
// Compile CodeCompileUnit using CodeProvider CSharpCodeProvider cc = new CSharpCodeProvider(); CompilerResults cr = cc.CompileAssemblyFromDom(cp, codeCompileUnit);
if (cr.Errors.HasErrors) { string errors = string.Empty; foreach (CompilerError error in cr.Errors) { errors += error.ErrorText + "\n"; } MessageBox.Show(errors, "Errors during compile."); }
|
示例程序使用CSharpCodeProvider 和VBCodeProvider生成代码,它也使用代码提供程序编译代码和运行可执行程序。
ITypeResolutionService是一个使用CodeDomDesignerLoader的时候的必须服务,负责类型解析。例如当从Toolbox添加一个控件到设计器的时候,这个服务被调用解析控件的类型。示例程序解析程序集System.Windows.Forms的所有类型,所以你能够将Toolbox的Windows Forms下的控件添加到设计器
结论 你所看到的是,.NET Framework提供了一个强大的和灵活的设计器宿主基础结构。比上一个版本的Visual Studio设计器的可扩展性有助于设计着解决特殊的需求或更多高级的场合. 当然, 设计者也能容易地宿主与Visual Studio外面 。同样地. 下载样例程序代码,你就能够参照例子设计你自己的设计器。
查看本文来源