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






4.83/5 (118投票s)
用户友好但功能强大的模板引擎,可实现内容与母版页(模板)的清晰、无痛分离。
引言
模板引擎允许您将 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
模板化发生的时间(在
OnInit
、OnLoad
、PreRender
期间或手动)。稍后会有更多说明。IgnoreOrderIndices
出于性能原因(默认),不检查模板化控件的
RenderIndex
属性(如下所述)。RegionTemplatePath
用于此 Web 表单的模板路径。
将区域分配给控件
一旦您的 Web 表单上有了 RegionProvider
,该组件就会通过两个新属性扩展表单上所有控件的属性(参见上面 Image
控件属性对话框的屏幕截图)
- 控件的
TargetRegion
属性告诉模板引擎在渲染时将您的控件放置在模板上的位置。在此示例中,图像将渲染到模板的区域Left1。 RenderIndex
属性控制进入同一区域的控件的顺序。您很少需要设置此项,并且只有在RegionProvider
的IgnoreRenderIndices
属性设置为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 表单的控件集合。
手动与自动模板化
RegionProvider
的 TemplateTime
属性允许您在给定时间执行模板化。在大多数情况下,您只需保留默认值即可。仍然,您有四种可能性
- 在 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 日。