主题和母版页(母版页)标准化网站布局的格式只是整个过程的一部分,你还需要保证通用的元素,如网站的标题、网站的导航控件等在每个页面里都出现在相同的位置。
解决这一问题的关键在于创建一个可以重复应用到整个网站的简单而灵活的布局。
有3 个基本办法可以选择:∙用户控件。
用户控件时标准化通用页面元素的优秀方式,但是,它们自身并不能解决页面布局的问题,因为没有办法保证用户控件在所有页面中都被放到同样的位置。
∙HTML 框架。
框架是在一个浏览器窗口中同时显示多个页面的HTML 基本工具。
它的主要缺点是它里面的每个页面必须通过单独请求服务器进行检索,这些页面的代码不得不完全独立。
这同时意味着一个框架里的页面不能和其他框架中的页面交互,也不能影响其他框架中的页面。
(至少不能通过服务器端代码)∙母版页。
母版页是 的一个特性,它专门设计用于标准化Web 页面布局。
它可定义固定的内容并声明Web 页面里可插入自定义内容的部分。
如果在整个网站中使用同一个母版页,就可以确保获得同样的布局。
最妙的是,如果修改了母版页的定义,应用它的所有页面都会自动变化。
要为页面模版提供一个可操作且灵活的解决方案,必须满足以下几个条件。
∙要能够单独定义页面的某个部分并在多个页面里重用它。
∙要能够创建一个定义了可编辑区域的封闭布局。
重用这个模版的页面只能够在许可的区域内添加或修改内容。
∙页面能够对重用的元素做一些自定义。
∙可以声明性的绑定页面倒页面模版(不使用代码)或者能够在运行时动态绑定到页面。
∙可以用工具(如VS)设计一个使用页面模版的页面。
为了实现这一切, 定义了两种新的页面类型:母版页和内容页。
母版页和普通的Web 页面一样,它可以包含任何HTML、Web 控件甚至代码的组合。
母版页还可以包含内容占位符(定义的可修改区域)。
内容页引用一个母版页并获得它的布局和内容。
此外,内容页可以在任意的占位符里加入页面特定的内容。
换句话说,内容页将母版页没有定义的缺失了的内容填入母版页。
母版页和一般Web窗体的区别是:∙母版页由Master 指令开始,并提供和Page 指令相同的信息。
而所有Web 窗体都由Page 指令开始。
∙只有母版页才可以使用ContentPlaceHolder控件,这个控件是内容页可以插入内容的部分。
创建一个母版页后,会得到一个只包含2 个ContentPlaceHolder控件的空白页。
第一个是在<head>区域定义的,它让内容页面能够增加页面元数据,比如搜索关键字和样式表链接。
第二个也是更重要的ContentPlaceHolder被定义在<body>区域,它代表页面显示的内容。
另外,母版页不能被直接请求,要使用母版页,必须创建一个关联的内容页。
下面是个简单的母版页示例,它有一个静态的横幅,其后跟着一个ContentPlaceHolder控件,然后是一个页脚:<%@ Master Language="C#" AutoEventWireup="true"CodeFile="SiteTemplate.master.cs"Inherits="Chapter16_SiteTemplate" %><html xmlns="/1999/xhtml"><head runat="server"><title></title><asp:ContentPlaceHolder ID="head"runat="server"></asp:ContentPlaceHolder></head><body><form id="form1"runat="server"><div><div style="background: black; height: 87px; font-weight: bold; font-size: 20px;color: white; font-family: Verdana"><img align="left"src="headerleft.jpg"/><img align="right"src="headerright.jpg"/><br/><asp:ContentPlaceHolder ID="TitleContent"runat="server">My Site</asp:ContentPlaceHolder></div><br/><br/><asp:ContentPlaceHolder ID="ContentPlaceHolder1"runat="server"></asp:ContentPlaceHolder><br/><em>Copyright © 2008.</em></div></form></body></html>要在其他页面里使用母版页,必须在Page 指令里加入MasterPageFile特性:<%@ Page Title="" Language="C#"MasterPageFile="~/Chapter16/SiteTemplate.master" ... %>只设置MasterPageFile特性还不足以把普通的页面转变成内容页。
内容页必须定义要插入一个或多个ContentPlaceHolder控件的内容(并编写这些控件需要的代码)。
由于母版页已经提供了外壳,因此,试图在内容页中加入<html>、<head>、<body>之类的元素,则会产生一个错误。
要为ContentPlaceHolder提供内容,要用到另一个叫Content 的特殊控件。
ContentPlaceHolder和Content 控件具有一对一的关系。
对于母版页里的每个ContentPlaceHolder,内容页会提供一个对应的Content 控件(除非不准备为那个区域提供任何内容)。
通过匹配ContentPlaceHolder的ID 和对应的Content 控件的Content.ContentPlaceHolderID属性将它们对应起来。
<%@ Page Title="" Language="C#"MasterPageFile="~/Chapter16/SiteTemplate.master"AutoEventWireup="true" CodeFile="Default.aspx.cs"Inherits="Chapter16_Default" %><asp:Content ID="Content1"ContentPlaceHolderID="ContentPlaceHolder1"ru nat="Server"><p class="Code"style="margin: 0in 0.1in 0pt 0in"><span style="font-size: 10pt; font-family: TheSansMonoConNormal">Far out in the unchartedbackwaters of the unfashionable end of the western spiral arm of the Galaxy liesa small unregarded yellow sun.</span></p></asp:Content><asp:Content ContentPlaceHolderID="TitleContent"ID="Content2"runat="se rver">Custom Title</asp:Content>为了更好的理解母版页是如何工作的,值得通过跟踪(在Page 指令里加入Trace=true)来看看内容页。
借助这种方式可以了解控件的层次。
你会发现 首先为母版页创建控件对象,包括ContentPlaceHolder(它充当一个容器),接着它会把内容页的控件加入ContentPlaceHolder。
如果需要动态配置母版页或内容页,可以响应任意一个类中的Page.Load事件。
有时你可能会同时在母版页和内容页中使用初始化代码。
这种情况下,理解每个事件发生的顺序就很重要。
首先创建母版页控件,然后添加内容页的子控件。
然后它触发母版页的Page.Init事件,随后是内容页的Page.Init事件。
对于Page.Load事件,也是相同的步骤。
(如果有冲突,那么内容页的自定义会覆盖在母版页相同阶段所做的修改)母版页定义ContentPlaceHolder时可以包含默认的内容(内容页没有提供相应的Content 控件时才会使用的内容)。
内容页不能只使用母版页默认内容的一部分或只编辑这一部分。
这是不可能的,因为默认内容是保存在母版页里面而不是内容页中。
所有,要么完全使用,要么就全部替换它。
HTML 使用基于流的布局。
这意味着随着内容的增加,页面会被重新组织,其他一些内容会被挤到一边。
这样的布局会使得难以获得母版页预期的结果。
如果你不小心,就会破坏原本完美的布局,插入到<Content>标签的大量信息会把页面结构弄得乱七八糟。
为了控制这些问题,大部分母版页使用HTML 表格或者CSS 定位来控制布局。
使用表格时,基本原则是把整个页面或页面的部分分解到行和列里。
然后你就可以把ContentPlaceHolder加入到某个单元格里,从而保证其他内容多少会按照预期的那样对齐。