技术开发 频道

在MVC模式下的UI AOP用例


一个面向组件的构架

   构件是在.NET环境中直接或者间接执行ystem.ComponentModel.IComponent的接口类。
  下面这个简洁的列表是关于.NET框架中一些类型,.NET框架是这个意义下的构件。
• System.ComponentModel.Component:IComponent的基本实现,此IComponent通常作为基类型,为非可视构件服务。
• System.Web.UI.Control:所有ASP.NET控件的基类型,它直接操作IComponent
• System.Windows.窗体s.Control:是从System.ComponentModel.Component继承而来的,是所有Windows Forms控件的基类型。
• System.Data.DataSet:这个类型是从System.ComponentModel.MarshalByValueComponent继承而来的,它依次地实现IComponent。
• System.Diagnostics.EventLog: 是从System.ComponentModel.Component继承来的.

   可以看到,在.NET平台中,几乎所有的事物都是构件。这个类型作为构件带来的主要结果就是:集成开发环境拥有它自己的功能。集成开发环境为构件提供服务的的关键属性就是IComponent.Site.一个所谓的站点构件就是被放置在容器中的构件。这个内含包容是一般的内含包容,与可视化的内含包容没有任何关系。

   例如:一个ASP.NET服务器控件,当访问Web 窗体时,可以说它就是站点构件。它的Site属性(是IComponent接口实现的一部分)被设置到了宿主,而构件正好处在宿主这个地方,VS.NET里面是一个Microsoft.VisualStudio.Designer.Host.DesignSite类型实例。确切地说,当在窗体设计器中时,同一个对象类型被访问时,同一个对象类型就会被设置为一个Windows Forms用户控件的Site属性,而在设计时期,则被设置成一个非可视构件。在最后一个和前一个之间存在一些差别,当我们观察严格的意义上的(非可视IComponent实现)构件时,我们再讨论这些差别。
   类型ISite的Site属性包含一些成员,这些成员允许构件与其它构件、它的容器 (一个逻辑容器)以及由它自己提供的服务相交流。我们将学习这些功能,讨论怎样利用这些功能。因此整个程序结构就是: 




   容器是一个执行System.ComponentModel.I容器 (从现在开始只有I容器)的对象。在设计时期,容器总是一个Microsoft.VisualStudio.Designer.Host.DesignerHost实例。这个对象是构件VS.NET 集成开发环境功能的核心,因此更进一步研究。

宿主构件


   首先,让我们看一下DesignerHost类型,有时需要一个工具,此工具使用反射,而且此工具能显示一个程序集的非公共成员。其中一个这样的工具就是反射器,如果还没有使用它,强烈推荐使用,至少应该开始熟悉它。它是学习任何.NET程序集的内部结构最有价值(而且是免费)的工具。我们感兴趣的类型位于VS.NET安装(默认C:\Program Files\Microsoft Visual Studio .NET\Common7\集成开发环境)的Common7\集成开发环境子文件夹中的Microsoft.VisualStudio.dll程序集中。通过它的视窗-定制菜单,你要使反射器显示非公共成员。

    这个类型执行(在许多其它接口中)我们先前所谈到的IContainer接口,而且要求IContainer接口能包含构件,以及通过实现派生的Microsoft.VisualStudio.Designer.集成开发环境signerDocument接口,间接包含System.ComponentModel.Design.IDesignerHost接口。这个接口提供高级别层服务,例如创建构件以及破坏构件,访问与构件相联系的设计器等等。一个位于对象内部执行此System.ComponentModel.Design.IDesignerHost的构件被命名为寄宿构件,这意味着它可以利用被它自己提供的服务。现在只有DesignerHost执行此寄宿构件,但是其它集成开发环境s也会选择执行此寄宿构件。

   这个宿主包含能在组建中利用的大部分服务,通过构件Site属性,可以访问这些服务。当前这个宿主包含下列服务:IDesignerHost、 IComponentChangeService、 IExtenderProviderService、 IContainer、ITypeDescriptorFilterService、IMenuEditorService、 ISelectionService、 IMenuCommandService、IOleCommandTarget、 IHelpService、 IReferenceService、 IPropertyValueUIService and ManagedPropertiesService。可以看到构件可以利用大量的服务,在这篇文章中,我们将展示这些服务的使用方法。

   这些服务的接入点是IServiceProvider接口。DesignSite 和DesignerHost类型都间接地执行这个接口:




    这个接口仅仅包含一个方法GetService,此方法GetService接受一个Type,而此Type暗示重新找到的服务。例如:

IComponentChangeService ccs = (IComponentChangeService) 
host.GetService(typeof(IComponentChangeService));
    现在,DesignSite(通过构件Site属性可以访问此DesignSite)它自己提供两个服务:IDictionaryService 和IextenderListService。对其它服务的要求被传递到了宿主。

   不仅仅通过构件Site属性能直接访问到由VS.NET宿主提供的这些服务,而且从与它相连接的类型(通过属性连接这些类型)可以直接访问到由VS.NET宿主提供的这些服务。通过属性连接的这些类型为构件提供设计时期优越性能。其它类型完成程序结构。

设计时期程序结构


   除了构件-站点-容器程序结构,还有一些额外的方面,这些额外的方面组成一个含有丰富功能的平台,为构件提供进步了的设计时期支持。对于RAD工具,这一点是非常重要的,而且这一点对于提高程序员生产力也非常重要。如果开发者想成功的话,专业构件应该为开发者提供一个丰富的设计时期经验。

   通过Attributes,这些额外的功能被补充到构件。属性的每一个类型为构件指定一个不同的设计时期(其中一些是运行时期)功能。这个集成开发环境在两方面使用这些属性:设计图面以及它与代码后置的档案和属性浏览器的交流。注意:我们刚才所说的设计图面,不仅仅是指Windows 或者是Web Forms的设计图面,而且也指它们下面的构件,无论什么时候,当设计器访问非可视构件时,此构件是可视的。

   大部分设计时期功能都包含在System.Design.dll程序集,下面的图片显示了设计时期属性的类型以及它们的用途。



   在这个图表中没有显示更加一般的属性,例如:DescriptionAttribute, CategoryAttribute以及其它一般属性,这些属性提供一些限制的功能,这些属性主要被属性浏览器使用。然而,这里还有一些其它属性,这些属性为构件增添了一些更复杂的更好利用的特点,因为它们非常特殊,所以没有显示它们。当我们讨论到更高级的方案时将引用这些属性。

   这三个属性中,每一个属性都将另一个相联系的类型与构件连接起来。DesignerAttribute连接一个类型,此类型直接或者间接地执行System.ComponentModel.Design.IDesigner (例如:System.ComponentModel.Design.ComponentDesigner, System.Web.UI.Design.HtmlControlDesigner 或者System.Windows. Forms.Design.ControlDesigner).对于从System.ComponentModel.TypeConverter派生而来的类型,以及从System.Drawing.Design.UITypeEditor派生来的类型,TypeConverterAttribute对它们做同样的事情。

   下面分类中的这些属性是根据它们提供的设计时期增强层来分类的。
   • 基本层:图中没有包含这些属性
   • TypeConverter and Editor attributes. 中间层:TypeConverter和Editor属性
   • 高级层:Designer属性
  
    我们没有采用这个分类,因为许多属性允许提供简单的以及高级的设计时期功能。在文章的末尾,一切都会变得相当清晰。通过三个属性(以及相关联的类)提供了下面这些功能:
   • Designer:与设计器宿主相交流,提供不同的设计功能。在System.ComponentModel.Design.ComponentDesigner类型中。可以找到设计器提供的共同功能,此共同功能通常是设计器的基类型。例如:这里有成员把构件中的改变告知宿主,过滤宿主和属性浏览器将看到的属性。

   更加具体的功能需要依靠设计器的类型,而设计器类型则依靠设计器附属的构件类型。因此,System.Windows. Forms.Design.ControlDesigner(所有Windows Forms控件的基本类型)处理控件和它的子控件之间的麻烦事情,拖曳操作,鼠标移动等其它事情。另一方面,System.Web.UI.Design.ControlDesigner(所有Web Forms控件的基本类型)负责发送HTML,在设计时期显示控件,并且负责执行页面源(.aspx file)控件状态的持久性,以及显示错误等等。

   设计器通常处理设计时期内应用到构件整个生命周期的功能,而且设计器是程序结构中更加灵活的部分。

   • Editor:提供自定义用户接口,以此来编辑构件属性,并且有选择地在显示它的属性浏览器细胞里描绘一个属性值。无论什么时候,当一个与编辑相连接的属性准备改变时,可以通过属性浏览器访问它。编辑器样本就是System.Drawing.Design.FontEditor,当你点击类型System.Drawing.Font的属性下面的省略符号时,就可以显示此System.Drawing.Design.FontEditor(此省略符号在类型System.Drawing.Font的旁边),或者点击System.Drawing.Design.ColorEditor(此System.Drawing.Design.ColorEditor提供一个颜色选择对话框)。
你可能会注意到:它们是两个不同类型的编辑器:FontEditor作为模式对话框而出现(例如:在Windows Formss控件中),但是ColorEditor(在Windows 以及Web控件中)则显示为一个下曳的小玩意儿(像AnchorEditor一样,AnchorEditor也显示成一个下曳式的小玩意儿)

    • TypeConverter:这是目前为止最难分类,最难描绘的部分,因为它拥有几个功能。首先,它提供了一个广泛的方法集,其中许多方法都是虚拟的,用来转换对象到其它类型,或者把其它类型转换成对象。这个转换主要被属性浏览器运用,转换成对象的字符串表示法或者从对象的字符串表示法转换,而此对象的字符串表示法是用于展示属性值的。但是我们将看到可能应用其他转换,而且其它转换甚至会影响构件的代码序列化。

   它也可以为属性提供一个值的序列表,这个值的序列表也是以下曳模式而显示出来的。你可能想知道这个与“Converter”世界有什么关系,也许Editor中应该包含有这个功能。

    最后能过滤将出现在属性浏览器中的内容窗体。例如:想要过滤可编辑的属性(此可编辑的属性是建立在创建的自定义属性基础上的,而不是建立在默认BrowsableAttribute基础之上的)时,过滤内容窗体对此非常有帮助。这是一个高级案例,但是将注意到:通过ComponentDesigner(几乎所有设计器的基类型),也可以利用这个功能,同时也可以注意到,此功能不但允许过滤属性,也允许过滤事件。

   TypeConverter和Editor可以应用到一个个体特性中,或者直接应用到类型中。在上面的例子中,任何附带有此类型的一个属性的对象可以自动地将编辑器/转换器与它相连接。

    属性浏览器也会使用设计器的一些功能,例如:DesignerVerbs。我们将在后面讨论DesignerVerbs,以及举例说明每一个属性的样本和它们的使用。

根构件和设计器

   一些类型导致设计图面出现在我们drop其它构件的地方。一般来说,这种情况会出现在Web 窗体 (Page 类型)中, 一个 Windows Forms中,或者任何组件-继承类型。例如:你将注意到自定义类型或者ASP.NET特定控件中将不会出现这些情况。两个属性的结合使得集成开发环境能为类型提供一个设计图面。

   DesignerCategoryAttribute:属性的构造函数必须指定“Component” 类。
[System.ComponentModel.DesignerCategory("Component")]
  DesignerAttribute:必须传递带有基本设计器类型的超载,而且设计器必须执行IRootDesigner.
[System.ComponentModel.Designer(typeof(My根tDesigner), 
typeof(System.ComponentModel.Design.I根tDesigner)]
   IComponent接口执行最后一个属性。因此每一个直接或者间接执行这个接口的类型将有一个默认设计图面,双击构件类型时,如果此默认设计图面拥有正确的种类,我们可以看到这个默认设计图面。Component类型就是一个例子。

   在解决方案资源管理器中选择一个项目来编辑时,如果有正确的种类和根设计器,集成开发环境将示例根设计器,将设计图面显示给用户。它将创建构件的一个实例,使它称为设计器宿主的根组件。例如:在设计视图中,当拥有一些子构件的Web 窗体s页面被打开时,这就是对象之间的联系。



   下面的伪码显示了Page类型宣告以及引起这个行为的属性:
[Designer(typeof(Web窗体Designer), typeof(I根tDesigner))] 
public class Page
   WebFormsDesigner类型位于同一个文件夹的Microsoft.VSDesigner.dll程序集中,作为我们在前面提到的Microsoft.VisualStudio.dll。在其它事物之间的这个设计器是从System.ComponentModel.Design.ComponentDesigner继承来的,此设计器是大部分设计器的基本类型,而且也是IDesigner接口的默认实现。Windows Forms构件中也有类似的过程。
   IComponent包括下面的属性声明:

[Designer(typeof(ComponentDocumentDesigner), typeof(I根tDesigner)] 
[Designer(typeof(ComponentDesigner)]
public interface IComponent
   当构件是根构件时,第一个属性定义类型(此类型处理设计图面的显示)。当其它设计器被放到另一个构件内部时,例如:一个Web 窗体,其它设计器指定构件提供的行为。

   目前为止讨论到的程序结构有一个主要目标,那就是:通过提高设计时期经验,以此来提高程序员的生产力。这里有太多的功能不能一一探讨,但是在一篇具体的高度集成的应用程序文章中,而不是单独的例子中,我们就可以一一探讨这些问题。我们将执行一个MVC框架,此MVC框架允许Web 和Windows应用程序共享一个公共的代码基础,将可视的程序员/设计器从复杂的商业对象中分离出来。此结构框架将主要建立在非可视构件的基础之上,但是我们实现的大部分集成开发环境集成功能是可视化控件的对等物。

0
相关文章