65.9K
CodeProject 正在变化。 阅读更多。
Home

母版页的重新定义 - 一种基于组件的 ASP.NET 模板引擎

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (118投票s)

2004年9月2日

CPOL

9分钟阅读

viewsIcon

1067460

downloadIcon

4171

用户友好但功能强大的模板引擎,可实现内容与母版页(模板)的清晰、无痛分离。

引言

模板引擎允许您将 ASP.NET Web 表单的内容渲染为母版页(模板)的一部分。此模板引擎提供了一种分离 ASP.NET 模板和 Web 表单的新方法。

功能一览

  • 对 Web 表单所有设置的完整设计器支持 - 无需编码,无需额外 HTML。
  • 不改变您的设计,因为 Web 表单的 HTML 完全未被触及 - 所有设置都序列化到代码隐藏文件中。
  • Web 表单不需要自定义基类。
  • 由于 HTML 不会改变,您可以将模板引擎与现有 Web 表单一起使用,而无需调整您的设计。
  • 轻松移除 Web 表单上的模板绑定(每个 Web 表单只有一个组件)。
  • 只需在运行时分配不同的模板即可实现不同的布局。

背景

我评估过的模板引擎要么难以使用(需要大量自定义代码),要么强迫我根据某些要求设计我的 ASP.NET Web 表单(例如,将控件放入专用容器控件)。我想要的是内容和模板的完全干净分离,而无需修改任何 HTML 和现有 Web 表单 - 因此我提出了这个解决方案。它易于使用,大大加快了模板化网站的开发速度 - 我的新网站由该引擎提供支持,不到两天就完成了(主要是处理内容),因为我只需要在创建模板后定义内容。

基本思路

模板工作的一个重要部分是……模板!它们提供两件事

  • 网页的共同结构,如页眉、页脚和导航。
  • 所谓的区域 - 页面中获取单独内容的区域。

其他部分是您的个人 Web 表单。它们包含分配给所用模板区域的内容。简单来说,模板引擎通过两个步骤将您的 Web 表单与模板合并

  • 模板动态加载
  • Web 表单的内容移动到模板的目标区域中

最棒的是 - 一旦您拥有了模板,所有操作都通过放置在每个 Web 表单上的单个组件完成 - 无需自定义基类、编码和额外 HTML。

必备组件

本教程分为两部分

  • 我们将创建一个模板(普通的旧用户控件),它托管 RegionPlaceHolder 控件。
  • 为了将我们的 Web 表单与模板合并,我们将使用放置在 Web 表单上的 RegionProvider 组件。

要在您自己的项目中处理这些控件,您应该将它们添加到您的工具箱中,这样您就可以简单地将它们拖放到您的 Web 表单上。但是,查看示例应用程序不需要这样做。

创建模板

模板是一个用户控件(.ascx 文件),它派生自 Evolve.Portals.Framework.PortalTemplate。您可以通过两个步骤让您的模板运行起来

  • 创建一个新的用户控件(.ascx 文件)。
  • 在代码隐藏文件中,将基类从 System.Web.UI.UserControl 更改为 Evolve.Portals.Framework.PortalTemplate

剩下的是设计您的模板并定义获取内容的区域。同样,这非常简单

  • 像标准网页一样设计您的模板(HTML 和 ASP.NET 控件)。
  • 通过将 RegionPlaceHolder 服务器控件拖到您的模板上,完成您的工作。

RegionPlaceHolder 控件公开一个属性 - 区域名称。一个区域只是一个 enum,它使记住您的设置更容易。属性对话框将向您显示可能的区域列表。如果您认为它们不符合您的需求,您可以通过简单地更改源代码中的 PortalRegion enum 来定义您自己的区域名称。

使用控件的属性对话框,我将值Left1分配给左侧的RegionPlaceHolder控件,将值Content分配给右侧的占位符。这允许我在示例的左侧窗格(黄色)或内容部分(蓝色)中渲染内容。

就这样了 :-)

RegionProvider 组件

主力是一个名为RegionProvider的组件。它放置在您的 Web 表单上,以将它们链接到您的模板。由于它是一个组件而不是控件,因此 RegionProvider 的属性被序列化到代码隐藏文件中,而不是 Web 表单的 .aspx 文件中。因此,您的 HTML 保持完全不变,所有设置都被编译而不是后期绑定。

要将提供程序分配给页面,只需将其拖放到 Web 表单上。Visual Studio 然后将其显示在设计器窗口的底部。

RegionProvider 本身只公开四个属性,其中只有模板路径需要显式设置

  • DefaultRegion

    如果设置,Web 表单上所有没有区域的顶级控件都将移动到模板的这个区域中。

  • TemplatingTime

    模板化发生的时间(在 OnInitOnLoadPreRender 期间或手动)。稍后会有更多说明。

  • IgnoreOrderIndices

    出于性能原因(默认),不检查模板化控件的 RenderIndex 属性(如下所述)。

  • RegionTemplatePath

    用于此 Web 表单的模板路径。

将区域分配给控件

一旦您的 Web 表单上有了 RegionProvider,该组件就会通过两个新属性扩展表单上所有控件的属性(参见上面 Image 控件属性对话框的屏幕截图)

  • 控件的 TargetRegion 属性告诉模板引擎在渲染时将您的控件放置在模板上的位置。在此示例中,图像将渲染到模板的区域Left1
  • RenderIndex 属性控制进入同一区域的控件的顺序。您很少需要设置此项,并且只有在 RegionProviderIgnoreRenderIndices 属性设置为 false 时才会发生。

与控件的标准属性不同,这些设置被序列化到设计器的 IntializeComponent 方法中 - 您的 HTML 保持不变。您可以在 Web 表单的代码隐藏类中检查您的设置。它看起来像这样

// 

// regionProvider1

// 

this.regionProvider1.HookIntoRendering = true;
this.regionProvider1.HostingPage = this;
this.regionProvider1.PropertySets.Add(new 
  Evolve.Portals.Framework.RegionPropertySet(this.Image1, 
  Evolve.Portals.Framework.PortalRegion.Left1, 0));
this.regionProvider1.PropertySets.Add(new 
  Evolve.Portals.Framework.RegionPropertySet(this.HelperPanel1, 
  Evolve.Portals.Framework.PortalRegion.Content, 0));
this.regionProvider1.RegionTemplatePath = "templates/menutemplate.ascx";
DefaultRegions 和容器控件

当然,您不必设置表单上每个控件的区域。

  • 如果您使用像 Panel 这样的容器,您无需触及该容器中的控件。
  • 您也可以在 RegionProvider 本身中设置 DefaultRegion 属性,并将控件的区域保留为 None。所有没有显式设置的控件都将移动到此区域。当然,这将给模板引擎带来更多工作,因为它需要检查 Web 表单的控件集合。

手动与自动模板化

RegionProviderTemplateTime 属性允许您在给定时间执行模板化。在大多数情况下,您只需保留默认值即可。仍然,您有四种可能性

  • 在 Web 表单的 OnInit 事件期间自动合并内容。如果控件的事件处理在 OnLoad 模板化下不起作用,请选择此项。不幸的是,VB.NET 似乎无法处理此计时,因为在 VB 页面中,设计器代码在此事件发生之后才被调用。VB 开发人员需要在其 Init 方法中手动调用模板渲染器以模拟此功能(请参见下文)。
  • 在 Web 表单的 OnLoad 事件期间自动合并内容(默认)。
  • 在 Web 表单的 PreRender 事件期间自动合并内容。通常不建议(在使用此项之前,请确保您了解 ASP.NET 执行生命周期。
  • 手动触发。

如果您想手动操作,请将 TemplateTime 设置为 Manual,并在代码隐藏文件中某处添加以下代码

   //merge with template

   Evolve.Portals.Framework.TemplateRenderer.PerformTemplating(this);

强烈建议在渲染发生之前调用 PerformTemplating 方法(例如,通过覆盖 RenderChildren 事件)。如果您这样做,可能会出现客户端验证问题(感谢 Gareth Brown 发现此问题):由于 ASP.NET 再次重新注册 JavaScript 事件处理程序,这会导致客户端脚本混乱。

重要提示:TemplateTime 属性取代了第一个版本中的 HookIntoRendering 标志,该标志用于覆盖 Web 表单的渲染并导致上述客户端验证问题。如果您正在从早期版本更新,您的 IDE 将拒绝编译,因为 HookIntoRendering 已被标记为 Obsolete。要更正您的代码,只需尝试编译,双击错误消息,并删除代码隐藏文件中设置 HookIntoRendering 的行

this.regionProvider1.HookIntoRendering = true; //does not work anymore!

处理模板上的控件

注意:以下说明仅适用于模板上的控件,不适用于Web 表单上的控件。

模板和相对链接

如果您的模板包含图像或链接(或其他使用相对链接的控件),它们可能无法正常渲染。这是因为设计时图像的路径可能与运行时渲染 Web 表单的路径不同。但是,无论如何,使用相对链接都很容易

对于直接放置在模板上的图像或链接,使用波浪号 (~) 。在运行时,波浪号被渲染为 Web 应用程序的根路径 - 一个非常好的功能(更多信息请参见 ASP.NET PRO)。示例:~/img/mylogo.gif 而不是 ../../img/mylogo.gif

……再次:您只需考虑您的模板,而不是 Web 表单。

访问模板的控件

在模板引擎完成其工作之前,您的模板控件无法供 Web 表单使用。但是,我更建议在模板本身中处理模板逻辑,以确保模板和 Web 表单的清晰分离。

摆脱模板引擎

使用 ASP.NET 2.0 的母版页,您可能希望切换并摆脱此模板引擎。这是页面设计和模板化真正发挥作用的地方:由于 RegionProvider 没有生成额外的 HTML,如果您删除 RegionProvider 组件,则整个 Web 表单的所有设置都会一次性删除。

要求

强烈建议安装 .NET 1.1 的 Service Pack 1。一些用户发现在没有服务包的机器上生成了无效的 JavaScript。如果您无法安装 SP 并且需要创建 JavaScript 的控件,请使用 OnInit 作为模板化时间。

结论

组件(Web 表单上的 RegionProvider)和控件(模板上的 RegionPlaceHolder)的混合使得您的模板工作变得极其容易。它防止您在整个 Web 应用程序中散布额外的 HTML,并强制实现设计和开发的清晰分离。我希望您能像我一样喜欢它 :-)

新闻稿

随着在生产应用程序中使用该引擎的用户数量不断增长,我决定提供一份新闻稿,以便那些不想定期在此处查看的人保持最新。如果您愿意,可以订阅:此处

历史

  • 版本 1.0 - 2004 年 9 月 1 日
  • 更新文章和新示例:2004 年 9 月 24 日
  • 版本 1.0.1 - 引入了 TemplateTime 属性,它取代了 HookIntoRendering:2004 年 10 月 1 日
  • 版本 1.0.2 - 引入了 OnInit 模板化时间,解决了在某些条件下数据绑定控件的客户端脚本问题:2004 年 10 月 28 日。
© . All rights reserved.