标题：母版页
介绍
使用 ASP.NET 母版页可以为应用程序中的页创建一致的布局。单个母版页可以为应用程序中的所有页（或一组页）定义所需的外观和标准行为。然后可以创建包含要显示的内容的各个内容页。当用户请求内容页时，这些内容页将与母版页合并，从而产生将母版页的布局与内容页中的内容组合在一起的输出[1]。
母版页的使用与普通页面类似，可以在其中放置文件或者图形、任何的HTML控件和Web控件，后置代码等。母版页的扩展名以.master结尾，不能被浏览器直接查看。母版页必须在被其他页面使用后才能进行显示。
它的使用跟普通的页面一样，可以可视化的设计，也可以编写后置代码。与普通页面不一样的是，它可以包含ContentPlaceHolder控件，ContentPlaceHolder控件就是可以显示内容页面的区域。
母版页仅仅是一个页面模板，单独的母版页是不能被用户所访问的。单独的内容页也不能够使用。母版页和内容页有着严格对应关系。母版页中包含多少个ContentPlaceHolder控件，那么内容页中也必须设置与其相对应的Content控件。当客户端浏览器向服务器发出请求，要求浏览某个内容页面时，引擎将同时执行内容页和母版页的代码，并将最终结果发送给客户端浏览器。
母版页的优点
母版页具有下面的优点：
— 使用母版页可以集中处理页的通用功能，以便可以只在一个位置上进行更新。
— 使用母版页可以方便地创建一组控件和代码，并将结果应用于一组页。例如，可以在母版页上使用控件来创建一个应用于所有页的菜单。
— 通过允许控制占位符控件的呈现方式，母版页使您可以在细节上控制最终页的布局。
— 母版页提供一个对象模型，使用该对象模型可以从各个内容页自定义母版页。
示例代码
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %>
......
<form id="form1" runat="server">
<div>
<asp:contentplaceholder id="ContentPlaceHolder1" runat="server">
</asp:contentplaceholder>
</div>
</form>
......
注意：
1、这里的声明指示符是“<%@ Master...%>”
2、其内部包含<asp:contentplaceholder......>控件
内容页
扩展名是.aspx。
在建立内容页面的时候，在“添加新项”对话框中要选中“选择母版页”复选框。这样建立的页面就是内容页面，内容页面在显示的时候会把母版面的内容一起以水印淡化的形式显示出来，而在母版页中的ContentPlaceHolder控件区域会被内容页面中的Content控件替换，程序员可以在这里编写内容页面中的内容。
代码如下：
<%@ Page Language="C#" MasterPageFile="~/MasterPage/MP.master" AutoEventWireup="true" CodeFile="Show1.aspx.cs" Inherits="MasterPage_Show1" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
</asp:Content>
注意：
1、这里的声明指示符中多了一项MasterPageFile="~/MasterPage/MP.master"，这一项是在创建内容页面时根据“选择母版页”复选框的选中情况生成的。它指明了该页是内容页面，也指明了该内容页面的母版页是哪个页面。
2、“<asp:Content ......>”就是要在其中显示的内容。
编程须知
一、在母版页中编写后台代码，访问母版页中的控件：
与普通的aspx页面一样，双击按钮即可编写母版页中的代码
二、在内空页面中编写后台代码，访问内容页面中的控件：
与普通的aspx页面一样，双击按钮即可编写母版页中的代码
三、在内容页面中编写代码访问母版页中的控件：
在内容页面中有个Master对象，它是MasterPage类型，它代表当前内容页面的母版页。通过这个对象的FindControl方法，我们可以找到母版面中的控件，这样就可以在内容页面中操作母版页中的控件了。
TextBox txt = (TextBox)((MasterPage)Master).FindControl("txtMaster");
txt.Text = this.txtContent1.Text; ;
四、在内容页面中编写代码访问母版页中的属性和方法：
仍可能通过Master对象进行访问，只不过在这里要把Master对象转换成具体的母版页类型，然后再调用母版页中的属性和方不法。
这里要说明的是：母版页中要被内容页面调用的属性和方法必须是Public修改的。否则无法调到。
假设母版页中有下面的属性和方法：
public string TextValue
{
get
{
return this.txtMaster.Text;
}
set
{
this.txtMaster.Text = value;
}
}
public void show(string str)
{
txtMaster.Text = str;
} 
在内容页面中可以通过下代的代码来实现对母版页中方法的调用： 
((MasterPage_MP)Master).show(this.txtContent1.Text);
((MasterPage_MP)Master).TextValue = this.txtContent1.Text;
五、在母版页中访问内容页面的控件：
在母版页中可以通过在ContentPlaceHolder控件中调用FindControl方法来取得控件，然后对控件进行操作。
((TextBox)this.ContentPlaceHolder1.FindControl("txtContent1")).Text = this.txtMaster.Text;
六、在母版页中访问内容页面中的方法和属性：
在母版页中调用子页面中的属性和方法有点难度，因为我们无法像上一步中那样通过FindControl来找到方法和属性。
于是我们想到在母版面的声明指示符中加入下面的代码：
<%@ Reference Page="~/MasterPage/Show1.aspx" %>
在运行的时候回发现有错误，错误的内容是“无法实现循环引用”。这是因为默认在子页面中引用了母版页，你也就不能再在母版页中引用子页面了。
我在网上也没找到更好的解决方法，但这使我们想起C#是的“反射”，它可以使我们动态获取页面对象，并且可以调用它的属性和方法。
代码如下：
Type t = this.ContentPlaceHolder1.Page.GetType();
PropertyInfo pi = t.GetProperty("ContentValue"); //获取ContentValue属性
pi.SetValue(this.ContentPlaceHolder1.Page,this.txtMaster.Text,null);    //给属性赋值
MethodInfo mi = t.GetMethod("SetValue"); //获取SetValue()方法
object[] os = new object[1];   //建造输入参数
os[0] = txtMaster.Text;
mi.Invoke(this.ContentPlaceHolder1.Page, os);    //调用SetValue方法
七、在有多个内容页面使用母版面的情况下，在母版页中根据不同的内容页面实现不同的操作
在母版页中可以加入多个不同的内容页面，但在设计期间，我们无法知道当前运行的是哪个内容页面。所以只能通过分支判断当前运行的是哪个子页面，来执行不同的操作。这里也用到了反射的知识。
代码如下：
string s = this.ContentPlaceHolder1.Page.GetType().ToString();   //取出内容页面的类型名称
if (s == "ASP.default17_aspx")   //根据不同的内容页面类型执行不同的操作
{
((TextBox)this.ContentPlaceHolder1.FindControl("TextBox2")).Text = "MastPage";
}
else if (s == "ASP.default18_aspx")
{
((TextBox)this.ContentPlaceHolder1.FindControl("TextBox2")).Text = "Hello MastPage";
}
八、在母版面与内容页面中JS代码的操作
在母版页或内容页面中的控件运行之后会自动生成ID，如文本框的ID是txtContent1，在运行之后ID会自动变为ctl00_ContentPlaceHolder2_txtContent1，name属性会变为ctl00$ContentPlaceHolder2$txtContent1。
在JS代码中，我们用document.getElementById()方法，根据id取得控件对象的时候，应当使用ctl00_ContentPlaceHolder2_txtContent1这个ID名，否则会产生“未找到对象”的异常。
母版页运行机制
母版页仅仅是一个页面模板，单独的母版页是不能被用户所访问的。单独的内容页也不能够使用。母版页和内容页有着严格对应关系。母版页中包含多少个ContentPlaceHolder控件，那么内容页中也必须设置与其相对应的Content控件。当客户端浏览器向服务器发出请求，要求浏览某个内容页面时，ASP.NET引擎将同时执行内容页和母版页的代码，并将最终结果发送给客户端浏览器。运行过程母版页和内容页的运行过程可以概括为以下5个步骤。
（1）用户通过键入内容页的URL来请求某页。
（2）获取内容页后，读取@ Page指令。如果该指令引用一个母版页，则也读取该母版页。如果是第一次请求这两个页，则两个页都要进行编译。
（3）母版页合并到内容页的控件树中。
（4）各个Content控件的内容合并到母版页中相应的ContentPlaceHolder控件中。
（5）呈现得到结果页。事件顺序（1）母版页中控件Init事件；
（2）内容页中Content控件Init事件；
（3）母版页Init事件；
（4）内容页Init事件；
（5）内容页Load事件；
（6）母版页Load事件；
（7）内容页中Content控件Load事件；
（8）内容页PreRender事件；
（9）母版页PreRender事件；
（10）母版页控件PreRender事件。
（11）内容页中Content控件PreRender事件。