The .NET Framework设计时框架是可扩展,提供的服务可用于实现各式各样的设计器。一个服务是提供对象可通过类型进行查询,典型的是你定义了服务的抽象类和接口和服务的实现。你可以从service container中添加或者删除服务。IDesignerHost是设计器主要的host接口,是一个Service Container。服务是一个组件间可以共享的,正因如此,在创建和使用Service的时候必须遵循确定的规则。
为了示范一下宿主一个设计器是多么简单,我写了下面的简单代码来创建一个基本的Windows? Forms designer并显示它:
// Create the DesignSurface and load it with a form
DesignSurface ds = new DesignSurface(); ds.BeginLoad(typeof(Form));
// Get the View of the DesignSurface, host it in a form, and show it
Control c = ds.View as Control; Form f = new Form(); c.Parent = f; c.Dock = DockStyle.Fill; f.Show(); 在这一个代码片断中,我已经用Form方式装载 DesignSurface. 同样地,你能用拥有根设计器的任何组件装载 DesignSurface. 举例来说,你可以改为装载 UserControl 或一个组件.
Figure 6 Hosting Windows Forms Designer
提供下载的例子代码中有四种根组件:Form, UserControl, Component, and MyTopLevelComponent (一个图形设计器). 当你运行例子的时候,一个Shell UI 将会打开. 它包括一个工具箱,一个属性窗口, 一个tab Control来宿主设计器,一个Output window和一个Solution EXPlorer,如图6所示..使用菜单的File New Form 用窗口打开一个新的Windows Forms Designer。这本质上就是使用上面所展示的代码加载一个设计器。与装载一个Form相比较,例子中还展示了如何装载UserControl或者组件。
DesignSurface 提供的主要服务之一是 IDesignerHost,IDesignerHost是用于提供设计器和对类型、服务和事务控制的主要接口。它也用于创建和销毁组件。添加一个按钮到Windows Forms designer所要做的工作就是从DesignSurface获得IDesignerHost接口并创建button,代码如图7
// Add a Button to the Form IDesignerHost idh = (IDesignerHost)ds.GetService(typeof(IDesignerHost)); Button b = (Button)idh.CreateComponent(typeof(Button)); // Set the Parent of this Button to the RootComponent (the Form) b.Parent = (Form)idh.RootComponent; // Use ComponentChangeService to announce changing of the // Form's Controls collection */ IComponentChangeService icc = (IComponentChangeService) idh.GetService(typeof(IComponentChangeService)); icc.OnComponentChanging(idh.RootComponent, TypeDescriptor.GetProperties(idh.RootComponent)["Controls");
// Load it using a Loader ds.BeginLoad(new MyLoader()); DesignerLoader 负责载入 DesignSurface 的根组件而且创建任何组件. 当创造一个新的Form或任何其他的根组件的时候,载入程序只是装载它. 和从代码文件或一些其他的存储介质的载入,载入程序负责解析文件或者存储而且再创建根组件的任何其他的必需组件.
示例应用中你可以选择菜单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."); }