用.NET Framework 2.0创建 Form设计器[翻译]

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:
 这两天赶鸭子上驾 , 学习 Form 设计器,下面这篇在 Msdn Magazine 的文章可谓是经典,这两天学习了感觉还是做个翻译出来,更能够加强理解。对各位同学也有帮助。我的英文水平不好,就来个中英文对照。对翻译有不对的地方,大家给纠正一下。 英文原文地址: [url]http://msdn.microsoft.com/msdnmag/issues/06/03/DesignerHosting/[/url]

     Version 1.0 of the Microsoft® .NET Framework provided a very flexible design-time architecture, but offered virtually no implemented code to actually create and host designers. All of the hosting logic was implemented in Visual Studio® .NET, requiring third parties to rewrite all of this complex logic. This has now changed; the .NET Framework 2.0 introduces a set of classes that can be used to host designers right out of the box.

Figure 1   Runtime
   Microsoft® .NET Framework 1.0 提供了一个非常通用的设计时框架,但是没有提供任何实现代码来完成一个设计器, Visual Studio® .NET 实现了所有的复杂逻辑,要第三方去重新实现这个复杂的逻辑。 .NET Framework 2.0 引入了一组类能够用于设计器的实现。
To understand how .NET Framework designers work, it is important to know how designers are used. A designer is an object that only exists at design time and that connects to an object that normally exists at run time. The framework connects these two objects and provides a conduit for the design-time object to augment the behavior of the run-time object. At run time, a form and a button on that form are connected only through the parent/child relationship between the two controls (see Figure 1). There is no other object that controls the lifetime of these controls.
    理解 .NET Framework 如何工作,非常重要的是要了解设计器是如何使用的。设计器是负责管理设计界面上的组件的设计时期行为和表现的对象。框架关联设计时对象和运行时对象,为设计时组件提供了一个管道扩展运行时对象的行为。运行时, Form 上的一个 form button 这两个控件只是通过父子关系相关联,没有其他的对象来控制这些控件的生命周期。

Figure 2  
The picture looks a little more complex at design time. Both the form and the button have designers associated with them. Both objects are also connected to a host container (see Figure 2), which owns these two objects. The host container also provides services—such as selection services to select one or more objects at design time, and UI services for displaying messages, invoking help, and interacting with the development environment—that the objects and designers may use.
上面的图片看出设计时比较复杂, Form button 都有一个设计器相关联,两个对象都和 Host 容器相关联, host 容器拥有这两个对象, host 容器也提供服务 --- 例如选取服务处理设计时的组件选取,并跟踪所选取的组件, UI 服务用于显示对话,调用帮助系统和设计环境相联系。
The host container has many responsibilities. It creates components, binding them to designers and providing services to the components and designers it maintains. It loads designers from some sort of persistent state and saves them back to that state. The host container provides logic for undo, clipboard functions, and many other services that the designers rely upon to deliver a robust design-time environment.
Host container 有许多职责,包括创建组件、绑定组件到设计器和为组件和设计器提供服务。从持久化介质上加载组件和保存组件状态到持久化介质。 Host container 提供撤销、剪贴板功能和其他的服务等为实现鲁棒的设计器所依赖的功能。

Figure 3   Designer Hosting
The host container can also persist the state of the designer. To do this, it would use a designer loader. The designer loader may, in turn, use serializers to serialize the components, as shown in Figure 3.
host container 使用 designer loader 持久化设计器状态 designer loader 使用序列化机制序列化组件。
 
Extensibility with Services
The .NET Framework designer architecture is extensible. Critical to this extensibility, services provide the ability to enhance the functionality available to the various designers. A service is any object that can be queried by a type. Typically you would define some abstract class or interface that represents the service and then provide an implementation of that service. You can add services to and remove services from an object called a service container. IDesignerHost, the primary host interface for designers, is a service container. A service is a feature that may be shared between components written by different parties. Because of this, you must follow certain rules when using and creating services.
The .NET Framework 设计时框架是可扩展,提供的服务可用于实现各式各样的设计器。一个服务是提供对象可通过类型进行查询,典型的是你定义了服务的抽象类和接口和服务的实现。你可以从 service container 中添加或者删除服务。 IDesignerHost 是设计器主要的 host 接口,是一个 Service Container 。服务是一个组件间可以共享的,正因如此,在创建和使用 Service 的时候必须遵循确定的规则。
Services are not guaranteed. Whenever you ask for a service by calling the GetService method, you must always check to see whether GetService returned a valid object. Not all services are available on all platforms, and services that were once available may not be available in the future. Thus, your code should be written to degrade gracefully, usually by disabling the feature that required the service, in case a service does become unavailable.
If you add a service, remember to remove it when your designer is disposed. The designer host may destroy and recreate your designer from time to time. If you fail to remove a service, the old designer may be left in memory.
Services 不被保证的,无论何时通过 GetService 方法请求一个服务( Services ),你一定要检查返回的是否是一个有效对象。并不是所有的服务在所有的平台上都是可用的,而且曾经可用的服务未来不可能是可得。因此你的代码应当被写的降低优雅型,通常籍由需要某种服务而丢失某些特性,以防万一一个服务也得不到。
如果你添加一个服务,记得在设计器的被 disposed 的时候移除它。设计器会时不时地创建和消毁,如果你没有去清除一个服务的话,旧的设计器就会遗留在内存中。
DesignSurface and DesignSurfaceManager
The .NET Framework 2.0 introduces two classes that are used for hosting designers and providing services to the designers: DesignSurface and DesignSurfaceManager. DesignSurface is what the user perceives as a designer; it is the UI the user manipulates to change design-time features. DesignSurface may be used as a standalone designer or it may be coupled with DesignSurfaceManager to provide a common implementation for an application that hosts multiple DesignSurfaces.
.NET Framework 2.0 引入了两个类 DesignSurface  DesignSurfaceManager. 给设计器提供宿主以及给设计器提供服务。 DesignSurface 是使用者所感知的设计器,它是 UI 使用者操纵改变设计时特征, DesignSurface  可能被当作一个单独的设计者使用或者和 DesignSurfaceManager 结合使用为设计器应用程序提供多个 DesignSurface
DesignSurface provides several design-time services automatically (see Figure 4). Most of these can be overridden in the service container. It is illegal to replace the non-replaceable services because their implementations all depend on each other. Note that all services added to the service container that implement IDisposable will be disposed when the design surface is disposed.
DesignSurface 提供好几个设计时服务,大多数服务都可以在服务容器中被覆盖,替换不可替换的服务是非法的,因为他们之间彼此仰赖 . 注意添加到 Service Containe 实现了接口 IDisposabler 的服务当 DesignSurface  销毁的时候都会被销毁。
In addition to the default services, DesignSurface also provides IDictionaryService, available through a component's site. This service, which provides a generic dictionary of key/value pairs that can be used to store arbitrary data about a component, is unique to each component. It is not possible to replace these services because there is no way to replace services on a per-site basis.
除了提供缺省的服务, DesignSurface 也提供了 IDictionaryService ,此服务提供一个使用关联键设置、检索和查找对象的简单接口。不可能替换这些服务因为在每个站点上无法替换这些服务。
DesignSurfaceManager is intended to be a container of designers. It provides common services that handle event routing between designers, property windows, and other global objects. Using DesignSurfaceManager is optional, but recommended if you intend to have several designer windows.
DesignSurfaceManager 是设计器的容器,它提供通用的服务以处理在设计者,属性窗口和其他的全局对象之间的事件路由 使用  DesignSurfaceManager 是可选择的 但是如果你想需要有一组设计者窗口,推荐使用 DesignSurfaceManager
DesignSurfaceManager also provides several design-time services automatically (see Figure 5). Each of these can be overridden by replacing their value in the protected ServiceContainer property. As with DesignSurface, all DesignSurfaceManager services added to the service container that implement IDisposable will be disposed when the designer application is disposed.
DesignSurfaceManager 也提供了几个设计时服务 (see Figure 5). 。每一个都可以在 Protected 属性 ServiceContainer (服务容器)中被覆盖。和 DesignSurface 一样, DesignSurfaceManager 所有的   实现了接口 IDisposabler 的服务   当设计器应用程序销毁的时候都会被销毁。
IDesignerEventService is a particularly useful service. It allows an application to know when a designer becomes active. IDesignerEventService provides a collection of designers and is a single place where global objects, such as the Property window, can listen to selection change events.
IDesignerEventService  是一个特别地有用的服务   当一个设计器变成活跃的时候  ,  它允许一个设计器应用程序被通知到 . IDesignerEventService 提供了一组设计器和全局对象的访问点 例如属性窗口能够侦听到选择变化事件 .

The Hosting Form
宿主 form
To demonstrate how simple it is to host a designer, I wrote the following sample code to create a basic Windows® Forms designer and display it:
为了示范一下宿主一个设计器是多么简单,我写了下面的简单代码来创建一个基本的 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();
In this code snippet, I have loaded the DesignSurface with a Form. Similarly, you can load the DesignSurface with any component that has a root designer available for it. For example, you could load a UserControl or a Component instead.
在这一个代码片断中,我已经用 Form 方式装载  DesignSurface.  同样地,你能用拥有根设计器的任何组件装载  DesignSurface.   举例来说,你可以改为装载  UserControl  或一个组件 .
The sample provided in the code download for this article hosts four different root components: Form, UserControl, Component, and MyTopLevelComponent (a graph designer). When you run the sample, a shell UI will open. This interface includes a toolbox, a properties browser, a tab control for hosting designers, an output window, and a Solution Explorer, as shown in Figure 6. Selecting File | New | Form from the menu opens a new designer host with Windows Forms Designer. This essentially uses the code I've just shown you to load the designer. Rather than loading a Form, the sample app illustrates how to load a UserControl or Component.

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 或者组件。
To create a root component, create a designer that implements IRootDesigner and then associate this designer with your component. The View property of the root component specifies the view that will be presented to the user.
创建一个根组件,也就是创建一个设计器实现 IRootDesigner 接口,然后指定这个组件的 designer 相关联,根组件的视图属性将呈现给使用者 .
One of the main services provided by DesignSurface is IDesignerHost. It is the master interface used to provide designers and controls access to types, services, and transactions. It can also be used to create and destroy components. To add a button to the Windows Forms designer I created earlier, all I need to do is get the IDesignerHost service from the DesignSurface and use it to create the button as shown in Figure 7.
DesignSurface  提供的主要服务之一是  IDesignerHost IDesignerHost 是用于提供设计器和对类型、服务和事务控制的主要接口。它也用于创建和销毁组件。添加一个按钮到 Windows Forms designer 所要做的工作就是从 DesignSurface 获得 IDesignerHost 接口并创建 button, 代码如图 7
 
IToolboxUser specifies that the designer supports adding controls from the toolbox. This means that if you do have a toolbox that implements ToolboxService, you can use the IToolboxUser interface to add controls to the root component. For instance:
 
ItoolboxUser 指定设计器支持从 Toolbox 中增加控件到设计器,这意味着你确实需要一个实现 ToolboxService Toolbox ,你能够用 IToolboxUser 接口把控件添加到根组件。例如:
/* Add a Button to the Form using IToolboxUser */
IDesignerHost idh = (IDesignerHost)ds.GetService(typeof(IDesignerHost));
IToolboxUser itu = (IToolboxUser)idh.GetDesigner(idh.RootComponent);
itu.ToolPicked(new ToolboxItem(typeof(Button)));
When controls are added to the custom RootDesigner in the sample application by double-clicking the items in the toolbox, the view of the RootDesigner updates to display a pie chart as shown in Figure 8. Clicking on the GraphStyle link changes the view to a bar graph.

Figure 8   Custom RootDesigner Updates
例子程序中双击 Toolbox 中的控件,控件被添加到自定义的根设计器,根设计器的视图中显示一个 pie chart 如图 8 所示,点击 GraphStyle 链接改变视图到 bar graph.
The Toolbox
MyRootDesigner implements the IToolboxUser interface. This has two methods: GetToolSupported and ToolPicked. You can use GetToolSupported to filter the items that can be added onto the designer. ToolPicked eventually calls into the CreateComponents method (which, as the name implies, is responsible for creating the components) of ToolboxItem.
 
MyRootDesigner 实现 IToolboxUser 接口,这个接口有两个方法: GetToolSupported and ToolPicked.  你能使用  GetToolSupported  过滤项目能被填加到设计器上的组件 进入 ToolboxItem   CreateComponents  方法  ( 如名字应用 , 负责创造组件 调用的时候调用 ToolPicked
 
Now that I have added the controls and components to the designer, let's take a closer look at how to implement a toolbox. First, your toolbox needs to implement IToolboxService—this service is added to the service container and can be accessed by anyone who needs to use it. The main functions of IToolboxService are shown in Figure 9.
既然我们已经成功添加控件和组件到设计器,让我们来看一下如何实现一个 Toolbox 。首先,你的工具箱需要实现  IToolboxService  —这一个服务被增加到服务容器,任何需要使用的任何人都可以被存取。 . ItoolboxService 的主要功能如图 9 所示。
 
To allow the items from the toolbox to be added onto the designer using the mouse or keyboard, the toolbox in the sample hooks onto the KeyDown and MouseDown events. For the Enter key or a mouse double-click, IToolboxUser.ToolPicked is called. The sample shows how to serialize the ToolboxItem into DataObject and DoDragDrop for when a mouse single-click event occurs. IToolboxService.SerializeToolboxItem will be called on mouse up and the item will be added to the designer.
允许项目从工具箱通过老鼠或键盘的添加到设计器上 , 示例程序的工具箱处理 KeyDown   MouseDown  事件。 Enter 键或鼠标双击事件,  IToolboxUser.ToolPicked  被调用 示例展示了鼠标单击拖动控件如何序列化 ToolboxItem   DataObject DoDragDrop 方法调用,鼠标 mouse up 事件 IToolboxService.SerializeToolboxItem 被调用,而且项目将会被增加到设计器 .
 
When a new control or component is added to the designer, you can provide a custom name for the control by implementing INameCreationService. The sample application shows an example of this service in action using CreateName, ValidateName, and IsValidName.
     当一个控件或者组件被添加到设计器,你能藉由实现  INameCreationService  提供一个定制的名字给组件,示例程序展示了 CreateName, ValidateName, and IsValidName 的代码实现。
 
Multiple DesignSurfaces
When managing multiple DesignSurfaces, it is a good idea to use a DesignSurfaceManager. This makes it easier to manage these DesignSurfaces. (Note that the services of DesignSurfaceManager are also available to DesignSurface.)
当管理多个 DesignSurfaces ,一个好主意是使用 DesignSurfaceManager 。它使得容易管理这些 DesignSurfaces( 注意  DesignSurfaceManager  的服务也是可得的到  DesignSurface.)
Calling DesignSurfaceManager.CreateDesignSurface calls into CreateDesignSurfaceCore. You can override this function to create a custom DesignSurface and add the services. The sample app creates a custom HostSurface by overriding this function in the HostSurfaceManager class:
调用 DesignSurfaceManager.CreateDesignSurface 将调用 CreateDesignSurfaceCore ,你能够重写这个函数去创建一个自定义的 DesignSurface 和增加服务。示例程序在类 HostSurfaceManager 通过重写这个函数创建了自定义的 HostSurface
protected override DesignSurface CreateDesignSurfaceCore(
    IServiceProvider parentProvider)
{
    return new HostSurface(parentProvider);
}
You can then hook into the ActiveDesignSurfaceChanged event and update the output window in the HostSurfaceManager class, as shown here:
你能通过 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";
So far I've created DesignSurfaces, hosted designers, added controls, implemented a toolbox, and added and accessed services like OutputWindow. The next step is to persist the designer. The designer loader is, as you'd expect, responsible for loading the designer from some persistent state. Simple and flexible, designer loaders have very few requirements. In fact, you can create an instance of the Windows Forms designer with a one-line designer loader that simply creates an instance of System.Windows.Forms.Form.
到现在为止我已经实现了 DesignSurfaces 、宿主设计器、添加控件、 Toolbox 和存取服务,像  OutputWindow.  下一个步骤要持久化设计器。设计器载入程序如同你将会期待一样 负责从持久化介质加载 Designer form.  设计器载入程序只有少许的需求 事实上,你能创建 Windows Forms designer 的一个实例。
In addition to loading a form design, a designer loader is also responsible for saving the design. Because saving is an optional behavior, a designer loader listens to change events from the designer host and automatically saves state according to these events.
除了载入设计器,设计器载入程序对设计结果的保存也是设计器的职责。因为保存是可选择的行为 , 一个设计者载入程序侦听改变来自设计器的改变事件,而且自动的保存这些状态。 .
The .NET Framework 2.0 introduces two new classes for writing custom loaders: BasicDesignerLoader and CodeDomDesignerLoader. The sample app illustrates implementations of both loader types. Earlier I demonstrated loading the DesignSurface with a root component by passing in the type of the component. However, if you are using a loader, it should be used to load the design surface. The BeginLoad code snippet you'll need when using loaders should look something like this:
.NET Framework 2.0 引入两个新的类来自定义加载器: BasicDesignerLoader  CodeDomDesignerLoader ,示例应用举例说明两者的载入程序类型的实现。然而,如果你正在使用一个载入程序 , 它应该用来装载 DesignSurface.  你将使用的  BeginLoad  代码片断当使用载入程序的时候应该看起来有点像下面的代码 :
// Load it using a Loader
ds.BeginLoad(new MyLoader());
The DesignerLoader is responsible for loading the root component in the DesignSurface and creating any components. When creating a new form or any other root component, the loader simply loads it. In comparison, when loading from a code file or some other store, the loader is responsible for parsing the file or store and recreating the root component along with any other necessary components.
 
DesignerLoader  负责载入  DesignSurface  的根组件而且创建任何组件 当创造一个新的 Form 或任何其他的根组件的时候,载入程序只是装载它 和从代码文件或一些其他的存储介质的载入 , 载入程序负责解析文件或者存储而且再创建根组件的任何其他的必需组件 .
The .NET Framework defines an abstract base class called DesignerLoader that is used to load and save designers from persistent storage. The base class is abstract so that any type of persistence model can be used. This, however, adds to the complexity of implementing the class.
.NET Framework 定义了一个抽象基类叫做 DesignerLoader ,用于加载和保存设计器到持久介质。基类是 abstract ,因此任何持久化模型都可以使用这个类,但是,这也增加了实现类的复杂性。
BasicDesignerLoader provides a complete and common implementation of a designer loader minus any information related to the persistence format. Like DesignerLoader, it is abstract, not dictating anything about the persistence format. BasicDesignerLoader does, however, handle the standard work of knowing when to save, knowing how to reload, and tracking change notifications from designers. Its features include support for multiple load dependencies, tracking of the modified bit to indicate a need to save changes, and deferred idle time reload support.
BasicDesignerLoader 提供了除任何数据的持久格式外设计者载入程序的完全和通常的实现  DesignerLoader  ,它是 abstract,  不处理关于持久化格式的任何事情 .  BasicDesignerLoader 处理标准的工作:如何时该保存 , 知道该如何再装载 而且追踪来自设计器的变化通知 它的特征包括对多依赖加载 , 保存变化 而且延期加载支持 .
The services shown in  Figure 10  are added to the designer host's service container by BasicDesignerLoader. As with other services, you can change replaceable services by editing their value in the protected LoaderHost property.The sample app implements a BasicDesignerLoader that persists the state in an XML format. To see how it works, select File | Type | BasicDesignerLoader. Then create a new Form by selecting File | New | Form. To see the XML code that is generated, select View | Code | XML. The XML code that is generated by the app will look something like this:
10 所示的服务被  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>
PerformFlush and PerformLoad are the two abstract functions of the BasicDesignerLoader that you need to implement for serializing and deserializing, respectively.
 
BasicDesignerLoader PerformFlush   PerformLoad  是二个 abstract 方法是你为实现序列化和反序列化的功能必须实现的方法 .
 
CodeDomDesignerLoader
Design-time serialization is handled by generating source code. One of the challenges of any code-generation scheme is the handling of multiple languages. The .NET Framework is designed to work with a variety of languages, so I also want the designers to emit to several languages. There are two ways to address this. The first is to require each language vendor to write the code-generation engine for their language. Unfortunately, no language vendor can anticipate the wide variety of code-generation requirements that third-party component vendors may need. The second approach is to require each component vendor to provide code generation for each language they want to support. This is equally bad, because the number of languages supported is not fixed.
设计时序列化是通过产生代码来实现,代码生成 Schema 的一个挑战是如何处理多语言。 .NET Framework 被设计为多语言协同工作,因此我也希望设计器能够生成多语言。有二个方法来达到解决这个问题 第一要需要每个语言厂商为他们的语言写代码生成引擎 不幸的是,没有语言厂商能够预期第三方组件厂商代码生成的多样性需求 第二种方式要需要每个组件厂商提供代码生成器给他们支持的每种语言 . 因为被支持的语言的数量是未知的,所以这相当糟糕。
To solve this problem, the .NET Framework defines an object model called the Code Document Object Model (CodeDOM). All source code can essentially be broken down into primitive elements and the CodeDOM is an object model for those elements. When code adheres to CodeDOM, the generated object model can later be sent to a code generator for a particular language to render the appropriate code.
  为了解决这个问题, .Net Framework 定义了一个对象模型叫做 代码文档对象模型(CodeDOM) 所有的原始代码能本质上分解为原始的元素的组合,而且  CodeDOM  是那些元素的对象模型 . 当代码依附在 CodeDOM,  生成的对象模型能够给不同语言的代码生成器生成适当的代码。
The .NET Framework 2.0 introduces CodeDomDesignerLoader, which inherits from BasicDesignerLoader. The CodeDomDesignerLoader is a full loader that works by reading and writing CodeDOM. It is a turnkey designer loader, so all you need to do is provide the CodeDOM.
.NET Framework 2.0 引入了 CodeDomDesignerLoader 类,继承自 BasicDesignerLoader CodeDomDesignerLoader 是一个通过 CodeDom 进行读写支持的全功能的加载器。它是设计者加载器 因而你所需要做全部的是CodeDomProvider .
In the sample app you can select File | Type | CodeDomDesigner-Loader to see an example of the CodeDOM in action. Create a new form by selecting File | New | Form—this creates a DesignSurface and loads it using a CodeDomDesignerLoader. To check the code, select View | Code | C# to see the C# version of the form's code, or View | Code | VB to see the Visual Basic® version.
示例应用中你可以选择菜单 File | Type | CodeDomDesigner-Loader 来看 CodeDom 的实做例子。创建新的 Form 通过菜单 File | New | Form--- 这创建一个 DesignSurface 和用 CodeDomDesignerLoader 加载它。查看代码,通过选择菜单 View | Code | C# 查看 Form 生成的 C# 代码,或者选择菜单 View | Code | VB 查看 Visual Basic® 代码。
To generate the code, the sample app uses CSharpCodeProvider and VBCodeProvider. It also uses the code providers to compile the code and run the executable (see  Figure 11 ).
示例程序使用 CSharpCodeProvider  VBCodeProvider 生成代码,它也使用代码提供程序编译代码和运行可执行程序。
ITypeResolutionService, which is required when using the CodeDomDesignerLoader, is responsible for resolving a type. One scenario, for example, where this service is called to resolve types is when adding a control from the toolbox into the designer. The sample application resolves all types from the System.Windows.Forms assembly so that you can add controls from the Windows Forms tab of the toolbox.
ITypeResolutionService 是一个使用 CodeDomDesignerLoader 的时候的必须服务,负责类型解析。例如当从 Toolbox 添加一个控件到设计器的时候,这个服务被调用解析控件的类型。示例程序解析程序集 System.Windows.Forms 的所有类型,所以你能够将 Toolbox Windows Forms 下的控件添加到设计器
Conclusion
As you've seen, the .NET Framework provides a powerful and flexible designer hosting infrastructure. Designers provide straightforward extensibility that help to address very specific needs or more advanced scenarios than were supported by previous versions of Visual Studio. Of course, designers can be hosted easily outside Visual Studio, as well. Be sure to download the sample application, so you can play around with the code and start implementing your own custom designers today.
     你所看到的是, .NET Framework 提供了一个强大的和灵活的设计器宿主基础结构。比上一个版本的 Visual Studio 设计器的可扩展性有助于设计着解决特殊的需求或更多高级的场合 当然 设计者也能容易地宿主与 Visual Studio 外面   。同样地 下载样例程序代码 , 你就能够参照例子设计你自己的设计器。
Dinesh Chandnani  is a Software Design Engineer in Test for the .NET Client Team at Microsoft, working on designer hosting and other designer features. He started working for Microsoft in 2002 after completing his masters' degree in Computer Science at the Universityof Arizona.





本文转自 张善友 51CTO博客,原文链接:http://blog.51cto.com/shanyou/75055,如需转载请自行联系原作者
目录
相关文章
|
2月前
使用的是.NET Framework 4.0,并且需要使用SMTP协议发送电子邮件
使用的是.NET Framework 4.0,并且需要使用SMTP协议发送电子邮件
56 1
|
2月前
|
开发框架 缓存 监控
NET Framework 到 .NET 5/6 的迁移是重大的升级
本文详细介绍了从 .NET Framework 4.8 迁移到 .NET 5/6 的过程,通过具体案例分析了迁移策略与最佳实践,包括技术栈评估、代码迁移、依赖项更新及数据库访问层的调整,强调了分阶段迁移、保持代码可维护性及性能监控的重要性。
61 3
|
2月前
|
机器学习/深度学习 编解码 算法
【小样本图像分割-4】nnU-Net: Self-adapting Framework for U-Net-Based Medical Image Segmentation
《nnU-Net: 自适应框架用于基于U-Net的医学图像分割》是一篇2018年的论文,发表在Nature上。该研究提出了一种自适应的医学图像分割框架nnU-Net,能够自动调整模型的超参数以适应不同的数据集。通过2D和3D U-Net及级联U-Net的组合,nnU-Net在10个医学分割数据集上取得了卓越的性能,无需手动调整。该方法强调数据增强、预处理和训练策略等技巧,为医学图像分割提供了一个强大的解决方案。
95 0
【小样本图像分割-4】nnU-Net: Self-adapting Framework for U-Net-Based Medical Image Segmentation
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
本文讨论了在基于.NET 6和.NET Framework的WinForms项目中添加图表控件的不同方法。由于.NET 6的WinForms项目默认不包含Chart控件,可以通过NuGet包管理器安装如ScottPlot等图表插件。而对于基于.NET Framework的WinForms项目,Chart控件是默认存在的,也可以通过NuGet安装额外的图表插件,例如LiveCharts。文中提供了通过NuGet添加图表控件的步骤和截图说明。
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
|
4月前
|
开发框架 缓存 前端开发
实战.NET Framework 迁移到 .NET 5/6
从.NET Framework 迁移到.NET 5/6 是一次重要的技术革新,涵盖开发环境与应用架构的全面升级。本文通过具体案例详细解析迁移流程,包括评估现有应用、利用.NET Portability Analyzer 工具识别可移植代码、创建新项目、逐步迁移代码及处理依赖项更新等关键步骤。特别关注命名空间调整、JSON 序列化工具更换及数据库访问层重构等内容,旨在帮助开发者掌握最佳实践,确保迁移过程平稳高效,同时提升应用性能与可维护性。
151 2
|
4月前
|
开发框架 JSON 监控
实战指南:从 .NET Framework 迁移到 .NET 5/6 的策略与最佳实践
【8月更文挑战第28天】从 .NET Framework 迁移到 .NET 5/6 是一次重要的技术升级,涉及开发环境与应用架构的改进。本文通过具体案例分析,介绍迁移策略与最佳实践,帮助开发者顺利完成转变。
94 1
|
4月前
|
缓存 程序员
封装一个给 .NET Framework 用的内存缓存帮助类
封装一个给 .NET Framework 用的内存缓存帮助类
|
4月前
|
XML JSON 程序员
总结一下 .NET FrameWork 和 .NET Core 创建的项目的不同点
总结一下 .NET FrameWork 和 .NET Core 创建的项目的不同点
109 0
|
4月前
|
开发框架 前端开发 .NET
分享一个 ASP.NET WebForm 使用 Form Authentication 的例子
分享一个 ASP.NET WebForm 使用 Form Authentication 的例子
|
4月前
|
消息中间件 开发框架 .NET
闲话 .NET(7):.NET Core 能淘汰 .NET FrameWork 吗?
闲话 .NET(7):.NET Core 能淘汰 .NET FrameWork 吗?