MasterPage的另外一种实现方式
我们知道WEB页面最终呈现给用户的是HTML,如下所示的一种格式:<Html><body><form><table><tr><td>(.....每个页面公共部分)....<table><tr></td>(..每个页面私有部分)</td></tr></table></td></tr></table></body></Html>
为此我们可以建立一个模板页面,在<%和%>中的内容我们规定是每个页面的私有部分,这里的<%没有特别意义,只不过一个标志而已,如下我们可以建立一个MasterPage.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>模版页面</title>
</head>
<body>
<link href="../CSS/trafficprice.css" type="text/css" rel="stylesheet">
<table cellSpacing="0" cellPadding="0" width="100%" border="0" ID="Table1">
<tr bgColor="#336699">
<td colSpan="2" height="60">
<h1 class="style1">公司标头</h1>
</td>
</tr>
<tr>
<td colSpan="2"><%#TopMenu%></td>
</tr>
<tr>
<td colSpan="2"><%#UserStatus%></td> <!--~/UserControl/WebUserHelp.ascx -->
</tr>
<tr vAlign="top">
<td bgColor="#dbeaf5"><%~/UserControl/menu.ascx%></td>
<td width="100%"><%CONTENT%></td>
</tr>
<tr bgColor="#336699">
<td colSpan="2" height="30"><span class="style1">联系人、版权信息</span></td>
</tr> </table>
</body>
</html>
〈%CONTENT%〉是表示其中的内容将被应用模板的页面内容所取代。对于ASP。NET的页面生成情况,我们可以把所有的元素归结为三种控件LiteralControl,编译是就能确认的用户控件(叫做WebCtrl)在模本中以<%~/UserControl/menu.ascx%> ~/UserControl/menu.ascx表示用户控件的路径,还有一种情况就是编译是系统不知道具体的用户控件在运行时才知道的(比如用户没有权限执行用户控件的功能,那就没有必要加载该用户控件),我们暂且就他为延迟用户控件DelayDefCtrl,在模板中用〈%TopMenu%〉表示。针对上面三种情况,我们定义三种控件类(LiteralItem、WebCtrlItem、DelayDefItem),和一个基类(MasterPageItem)
using System;
using System.Web.UI;
![]()
namespace TrafficPrice.CommunalAccess.TempletPage
{
/// <summary>
/// MasterPageItem 的摘要说明。
/// </summary>
internal abstract class MasterPageItem {
public abstract Control CreateControl(BasePage paraPage);
}
}<%#TopMenu%><%#TopMenu%><%~/UserControl/menu.ascx%><%~/UserControl/menu.ascx%><%~/UserControl/menu.ascx%>
using System;
using System.Web.UI;
![]()
namespace TrafficPrice.CommunalAccess.TempletPage
{
/// <summary>
/// LiteralItem 的摘要说明。
/// </summary>
internal class LiteralItem : MasterPageItem {
private string memLiteral;
public LiteralItem(string paraLiteral) {
memLiteral = paraLiteral;
}
![]()
public override Control CreateControl(BasePage paraPage) {
return new LiteralControl(memLiteral);
}
}
}
using System;
using System.Web.UI;
![]()
namespace TrafficPrice.CommunalAccess.TempletPage
{
/// <summary>
/// WebCtrlItem 的摘要说明。
/// </summary>
internal class WebCtrlItem : MasterPageItem {
string memCtrlUri;
public WebCtrlItem(string paraCtrlUri) {
memCtrlUri = paraCtrlUri;
}
public override Control CreateControl(BasePage paraPage) {
return paraPage.LoadControl(memCtrlUri);
}
}
}
using System;
using System.Web.UI;
![]()
namespace TrafficPrice.CommunalAccess.TempletPage
{
/// <summary>
/// DelayDefItem 的摘要说明。
/// </summary>
internal class DelayDefItem : MasterPageItem {
private string memIndex;
![]()
public DelayDefItem(string paraIdx) {
memIndex = paraIdx;
}
public override Control CreateControl(BasePage paraPage) {
string tempCtrlUri = paraPage.MasterCtrlNameDir[memIndex] as string;
if ((tempCtrlUri!=null)&&(tempCtrlUri.Length>1))
return paraPage.LoadControl(tempCtrlUri);
return null;
}
}
}
接下来我们就可以分析模板页面并生成上面所说的三种控件,下面是具体的实现类(MasterPageTemplate.cs)
using System;
using System.IO;
using System.Text;
using System.Web;
using System.Collections;
using System.Collections.Specialized;
namespace TrafficPrice.CommunalAccess.TempletPage
{
/// <summary>
/// MasterPageTemplate 的摘要说明。
/// </summary>
internal class MasterPageTemplate {
private const string BodyStartTag = "<body>";
private const string BodyEndTag = "</body>";
private const string CtrlStartTag = "<%";
private const string CtrlEndTag = "%>";
private const string ContentTag = "CONTENT";
![]()
static private readonly Encoding memEncoding;
![]()
private IList templetctl = null;
![]()
static MasterPageTemplate() {
memEncoding = Encoding.GetEncoding(936);
}
![]()
public MasterPageTemplate(string paraUri) {//模板页的路径
string tempMasterPageTemplateFilename
= HttpContext.Current.Server.MapPath(paraUri);
string tempMasterPageTemplate;
using (StreamReader tempReader = new StreamReader(
tempMasterPageTemplateFilename,
memEncoding,
true)) {
tempMasterPageTemplate = tempReader.ReadToEnd();
}
int tempStart = tempMasterPageTemplate.IndexOf(BodyStartTag);
if (tempStart < 0)
return;
tempStart += BodyStartTag.Length;
templetctl=new ArrayList();
LoadItems(templetctl,tempMasterPageTemplate,tempStart);
}
![]()
/// <summary>
///
/// </summary>
/// <param name="paraList"></param>
/// <param name="paraTemplate"></param>
/// <param name="paraStart"></param>
/// <returns>true if still have data to read</returns>
static private void LoadItems(
IList ctllist, string paraTemplate, int paraStart) {
int tempTest, tempLen;
int tempStart = paraStart;
ArrayList paraList=new ArrayList();
![]()
while(true) {
tempTest = paraTemplate.IndexOf(CtrlStartTag,tempStart);
if (tempTest < 0) {
tempTest = paraTemplate.IndexOf(BodyEndTag);
if (tempTest < 0)
throw new ApplicationException(
"master page is invalid: no body end tag");
tempLen = tempTest - tempStart;
if (tempLen > 0) {
paraList.Add(new LiteralItem(
paraTemplate.Substring(tempStart,tempLen)));
}
ctllist.Add(paraList);
return; // end of body
}
tempLen = tempTest - tempStart;
if (tempLen > 0) {
paraList.Add(new LiteralItem(
paraTemplate.Substring(tempStart,tempLen)));
}
tempStart = tempTest + CtrlStartTag.Length;
tempTest = paraTemplate.IndexOf(CtrlEndTag,tempStart);
if (tempTest < 0)
throw new ApplicationException("Unclose tag");
tempLen = tempTest - tempStart;
if (tempLen == 0)
throw new ApplicationException("Empty control tag");
string tempUri = paraTemplate.Substring(tempStart, tempLen).Trim();
if (tempUri.Length == 0)
throw new ApplicationException("control is blank");
tempStart = tempTest + CtrlEndTag.Length;
if (tempUri == ContentTag) {
paraTemplate=paraTemplate.Substring(tempStart);
paraList.Reverse();
ctllist.Add(paraList);
LoadItems(ctllist,paraTemplate,0);
return;
}
if (tempUri[0]=='#')
paraList.Add(new DelayDefItem(tempUri));
else
paraList.Add(new WebCtrlItem(tempUri));
}
}
![]()
public IList TemCtl {
get {
return templetctl;
}
}
}
}
最后我们实现一个BasePage,它是一个继承自Page的一个类,我们让所有应用MasterPage的页面都继承这个类,通过重写CreateChildControls()方法,加载我们生成的三种控件。
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Security.Principal;
using System.Collections;
using System.Collections.Specialized;
//using TrafficPrice.CommunalAccess.DataDefine;
![]()
namespace TrafficPrice.CommunalAccess.TempletPage
{
/// <summary>
/// BasePage 的摘要说明。
/// </summary>
public class BasePage:Page
{
static private readonly IDictionary memMasterPages
= new HybridDictionary();
![]()
private string memMasterPageUri = null;
private MasterPageTemplate memTemplate = null;
private IDictionary memMasterCtrlNameDir = new HybridDictionary();
// private ProfileInformation profile=null;
public BasePage() {
}
![]()
public BasePage(string paraBasePageUri) {
memMasterPageUri=paraBasePageUri;
}
protected string PageUrl{
set{
memMasterPageUri=value;
}
}
![]()
![]()
![]()
public IDictionary MasterCtrlNameDir {
get {
return memMasterCtrlNameDir;
}
}
![]()
![]()
override protected void OnInit(EventArgs e) {
base.OnInit(e);
}
![]()
private Control GetControl(Type type, bool prefix) {
Control tempPlaceHolder = this.FindControl(prefix ? "memMasterPagePrefix" : "memMasterPageSuffix");
if (tempPlaceHolder == null)
return null;
ControlCollection container = tempPlaceHolder.Controls;
foreach(Control control in container) {
if (type.IsAssignableFrom(control.GetType()))
return control;
}
return null;
}
protected Control GetControl(Type type,string fatherCtl) {
Control tempPlaceHolder = this.FindControl(fatherCtl);
if (tempPlaceHolder == null)
return null;
ControlCollection container = tempPlaceHolder.Controls;
foreach(Control control in container) {
if (type.IsAssignableFrom(control.GetType()))
return control;
}
return null;
}
![]()
private void AddControls(
ControlCollection paraHost,IList paraList, bool paraAtHead) {
if (paraList == null)
return;
foreach (MasterPageItem tempItem in paraList) {
Control tempCtrl = tempItem.CreateControl(this);
if (tempCtrl != null) {
if (paraAtHead)
paraHost.AddAt(0,tempCtrl);
else
paraHost.Add(tempCtrl);
}
}
}
![]()
protected override void CreateChildControls() {
if ((memTemplate == null)
&&(memMasterPageUri!=null)&&(memMasterPageUri.Length>0)) {
memTemplate = memMasterPages[memMasterPageUri.ToLower()] as MasterPageTemplate;
if (memTemplate == null) {
memTemplate = new MasterPageTemplate(memMasterPageUri);
if (memTemplate != null)
memMasterPages[memMasterPageUri] = memTemplate;
}
}
![]()
base.CreateChildControls ();
![]()
if (memTemplate != null) {
Control tempForm = null;
foreach(Control tempCtrl in Controls) {
if (tempCtrl is HtmlForm) {
tempForm = tempCtrl;
break;
}
}
if (tempForm != null) {
ControlCollection tempHost = tempForm.Controls;
IList PlaceHolderCtl=new ArrayList();
foreach(Control tempControl in tempHost) {
if (tempControl.GetType().IsAssignableFrom(typeof(System.Web.UI.WebControls.PlaceHolder))) {
PlaceHolderCtl.Add(tempControl);
}
}
for(int i=0;i<PlaceHolderCtl.Count;i++){
if(i==PlaceHolderCtl.Count-1){
AddControls(((Control)PlaceHolderCtl[i]).Controls,(IList) memTemplate.TemCtl[i],false);
return;
}
AddControls(((Control)PlaceHolderCtl[i]).Controls, (IList) memTemplate.TemCtl[i],true);
}
}
}
}
}
}
下面是应用摸板的例子:
<%@ Register TagPrefix="uc1" TagName="pagenavigation" Src="../UserControl/pagenavigation.ascx" %>
<%@ Page language="c#" Codebehind="BrowBulkGoods.aspx.cs" AutoEventWireup="false" Inherits="TrafficPrice.SeaTransport.BrowBulkGoods" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>浏览散货信息</title>
<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<asp:placeholder id="memMasterPagePrefix" runat="server"></asp:placeholder>
<table cellSpacing="0" cellPadding="0" width="95%" border="0">
<tr>
<td vAlign="top">
<table cellSpacing="0" cellPadding="0" width="100%" border="0">
<tr>
<td>this is a test for apply MasterPage
</td>
</tr>
</table>
</td>
</tr>
</table>
<asp:placeholder id="memMasterPageSuffix" runat="server"></asp:placeholder></form>
</body>
</HTML>
注意被在两个<asp:placeholder id="memMasterPagePrefix" runat="server">包围的内容将取代摸板页中〈%CONTENT%〉中的内容。如果有多个〈%CONTENT%〉那么也应该有多个<asp:placeholder 来分割。当然该类继承自BasePage,基类的构造函数的参数为摸板页面的路径。
为此我们可以建立一个模板页面,在<%和%>中的内容我们规定是每个页面的私有部分,这里的<%没有特别意义,只不过一个标志而已,如下我们可以建立一个MasterPage.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>模版页面</title>
</head>
<body>
<link href="../CSS/trafficprice.css" type="text/css" rel="stylesheet">
<table cellSpacing="0" cellPadding="0" width="100%" border="0" ID="Table1">
<tr bgColor="#336699">
<td colSpan="2" height="60">
<h1 class="style1">公司标头</h1>
</td>
</tr>
<tr>
<td colSpan="2"><%#TopMenu%></td>
</tr>
<tr>
<td colSpan="2"><%#UserStatus%></td> <!--~/UserControl/WebUserHelp.ascx -->
</tr>
<tr vAlign="top">
<td bgColor="#dbeaf5"><%~/UserControl/menu.ascx%></td>
<td width="100%"><%CONTENT%></td>
</tr>
<tr bgColor="#336699">
<td colSpan="2" height="30"><span class="style1">联系人、版权信息</span></td>
</tr> </table>
</body>
</html>
using System;
using System.Web.UI;
namespace TrafficPrice.CommunalAccess.TempletPage
{
/// <summary>
/// MasterPageItem 的摘要说明。
/// </summary>
internal abstract class MasterPageItem {
public abstract Control CreateControl(BasePage paraPage);
}
}
using System;
using System.Web.UI;
namespace TrafficPrice.CommunalAccess.TempletPage
{
/// <summary>
/// LiteralItem 的摘要说明。
/// </summary>
internal class LiteralItem : MasterPageItem {
private string memLiteral;
public LiteralItem(string paraLiteral) {
memLiteral = paraLiteral;
}
public override Control CreateControl(BasePage paraPage) {
return new LiteralControl(memLiteral);
}
}
}
using System;
using System.Web.UI;
namespace TrafficPrice.CommunalAccess.TempletPage
{
/// <summary>
/// WebCtrlItem 的摘要说明。
/// </summary>
internal class WebCtrlItem : MasterPageItem {
string memCtrlUri;
public WebCtrlItem(string paraCtrlUri) {
memCtrlUri = paraCtrlUri;
}
public override Control CreateControl(BasePage paraPage) {
return paraPage.LoadControl(memCtrlUri);
}
}
}
using System;
using System.Web.UI;
namespace TrafficPrice.CommunalAccess.TempletPage
{
/// <summary>
/// DelayDefItem 的摘要说明。
/// </summary>
internal class DelayDefItem : MasterPageItem {
private string memIndex;
public DelayDefItem(string paraIdx) {
memIndex = paraIdx;
}
public override Control CreateControl(BasePage paraPage) {
string tempCtrlUri = paraPage.MasterCtrlNameDir[memIndex] as string;
if ((tempCtrlUri!=null)&&(tempCtrlUri.Length>1))
return paraPage.LoadControl(tempCtrlUri);
return null;
}
}
}
using System;
using System.IO;
using System.Text;
using System.Web;
using System.Collections;
using System.Collections.Specialized;
namespace TrafficPrice.CommunalAccess.TempletPage
{
/// <summary>
/// MasterPageTemplate 的摘要说明。
/// </summary>
internal class MasterPageTemplate {
private const string BodyStartTag = "<body>";
private const string BodyEndTag = "</body>";
private const string CtrlStartTag = "<%";
private const string CtrlEndTag = "%>";
private const string ContentTag = "CONTENT";
static private readonly Encoding memEncoding;
private IList templetctl = null;
static MasterPageTemplate() {
memEncoding = Encoding.GetEncoding(936);
}
public MasterPageTemplate(string paraUri) {//模板页的路径
string tempMasterPageTemplateFilename
= HttpContext.Current.Server.MapPath(paraUri);
string tempMasterPageTemplate;
using (StreamReader tempReader = new StreamReader(
tempMasterPageTemplateFilename,
memEncoding,
true)) {
tempMasterPageTemplate = tempReader.ReadToEnd();
}
int tempStart = tempMasterPageTemplate.IndexOf(BodyStartTag);
if (tempStart < 0)
return;
tempStart += BodyStartTag.Length;
templetctl=new ArrayList();
LoadItems(templetctl,tempMasterPageTemplate,tempStart);
}
/// <summary>
///
/// </summary>
/// <param name="paraList"></param>
/// <param name="paraTemplate"></param>
/// <param name="paraStart"></param>
/// <returns>true if still have data to read</returns>
static private void LoadItems(
IList ctllist, string paraTemplate, int paraStart) {
int tempTest, tempLen;
int tempStart = paraStart;
ArrayList paraList=new ArrayList();
while(true) {
tempTest = paraTemplate.IndexOf(CtrlStartTag,tempStart);
if (tempTest < 0) {
tempTest = paraTemplate.IndexOf(BodyEndTag);
if (tempTest < 0)
throw new ApplicationException(
"master page is invalid: no body end tag");
tempLen = tempTest - tempStart;
if (tempLen > 0) {
paraList.Add(new LiteralItem(
paraTemplate.Substring(tempStart,tempLen)));
}
ctllist.Add(paraList);
return; // end of body
}
tempLen = tempTest - tempStart;
if (tempLen > 0) {
paraList.Add(new LiteralItem(
paraTemplate.Substring(tempStart,tempLen)));
}
tempStart = tempTest + CtrlStartTag.Length;
tempTest = paraTemplate.IndexOf(CtrlEndTag,tempStart);
if (tempTest < 0)
throw new ApplicationException("Unclose tag");
tempLen = tempTest - tempStart;
if (tempLen == 0)
throw new ApplicationException("Empty control tag");
string tempUri = paraTemplate.Substring(tempStart, tempLen).Trim();
if (tempUri.Length == 0)
throw new ApplicationException("control is blank");
tempStart = tempTest + CtrlEndTag.Length;
if (tempUri == ContentTag) {
paraTemplate=paraTemplate.Substring(tempStart);
paraList.Reverse();
ctllist.Add(paraList);
LoadItems(ctllist,paraTemplate,0);
return;
}
if (tempUri[0]=='#')
paraList.Add(new DelayDefItem(tempUri));
else
paraList.Add(new WebCtrlItem(tempUri));
}
}
public IList TemCtl {
get {
return templetctl;
}
}
}
}
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Security.Principal;
using System.Collections;
using System.Collections.Specialized;
//using TrafficPrice.CommunalAccess.DataDefine;
namespace TrafficPrice.CommunalAccess.TempletPage
{
/// <summary>
/// BasePage 的摘要说明。
/// </summary>
public class BasePage:Page
{
static private readonly IDictionary memMasterPages
= new HybridDictionary();
private string memMasterPageUri = null;
private MasterPageTemplate memTemplate = null;
private IDictionary memMasterCtrlNameDir = new HybridDictionary();
// private ProfileInformation profile=null;
public BasePage() {
}
public BasePage(string paraBasePageUri) {
memMasterPageUri=paraBasePageUri;
}
protected string PageUrl{
set{
memMasterPageUri=value;
}
}



public IDictionary MasterCtrlNameDir {
get {
return memMasterCtrlNameDir;
}
} 

override protected void OnInit(EventArgs e) {
base.OnInit(e);
}
private Control GetControl(Type type, bool prefix) {
Control tempPlaceHolder = this.FindControl(prefix ? "memMasterPagePrefix" : "memMasterPageSuffix");
if (tempPlaceHolder == null)
return null;
ControlCollection container = tempPlaceHolder.Controls;
foreach(Control control in container) {
if (type.IsAssignableFrom(control.GetType()))
return control;
}
return null;
}
protected Control GetControl(Type type,string fatherCtl) {
Control tempPlaceHolder = this.FindControl(fatherCtl);
if (tempPlaceHolder == null)
return null;
ControlCollection container = tempPlaceHolder.Controls;
foreach(Control control in container) {
if (type.IsAssignableFrom(control.GetType()))
return control;
}
return null;
}
private void AddControls(
ControlCollection paraHost,IList paraList, bool paraAtHead) {
if (paraList == null)
return;
foreach (MasterPageItem tempItem in paraList) {
Control tempCtrl = tempItem.CreateControl(this);
if (tempCtrl != null) {
if (paraAtHead)
paraHost.AddAt(0,tempCtrl);
else
paraHost.Add(tempCtrl);
}
}
}
protected override void CreateChildControls() {
if ((memTemplate == null)
&&(memMasterPageUri!=null)&&(memMasterPageUri.Length>0)) {
memTemplate = memMasterPages[memMasterPageUri.ToLower()] as MasterPageTemplate;
if (memTemplate == null) {
memTemplate = new MasterPageTemplate(memMasterPageUri);
if (memTemplate != null)
memMasterPages[memMasterPageUri] = memTemplate;
}
}
base.CreateChildControls ();
if (memTemplate != null) {
Control tempForm = null;
foreach(Control tempCtrl in Controls) {
if (tempCtrl is HtmlForm) {
tempForm = tempCtrl;
break;
}
}
if (tempForm != null) {
ControlCollection tempHost = tempForm.Controls;
IList PlaceHolderCtl=new ArrayList();
foreach(Control tempControl in tempHost) {
if (tempControl.GetType().IsAssignableFrom(typeof(System.Web.UI.WebControls.PlaceHolder))) {
PlaceHolderCtl.Add(tempControl);
}
}
for(int i=0;i<PlaceHolderCtl.Count;i++){
if(i==PlaceHolderCtl.Count-1){
AddControls(((Control)PlaceHolderCtl[i]).Controls,(IList) memTemplate.TemCtl[i],false);
return;
}
AddControls(((Control)PlaceHolderCtl[i]).Controls, (IList) memTemplate.TemCtl[i],true);
}
}
}
}
}
}
<%@ Register TagPrefix="uc1" TagName="pagenavigation" Src="../UserControl/pagenavigation.ascx" %>
<%@ Page language="c#" Codebehind="BrowBulkGoods.aspx.cs" AutoEventWireup="false" Inherits="TrafficPrice.SeaTransport.BrowBulkGoods" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>浏览散货信息</title>
<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<asp:placeholder id="memMasterPagePrefix" runat="server"></asp:placeholder>
<table cellSpacing="0" cellPadding="0" width="95%" border="0">
<tr>
<td vAlign="top">
<table cellSpacing="0" cellPadding="0" width="100%" border="0">
<tr>
<td>this is a test for apply MasterPage
</td>
</tr>
</table>
</td>
</tr>
</table>
<asp:placeholder id="memMasterPageSuffix" runat="server"></asp:placeholder></form>
</body>
</HTML>


浙公网安备 33010602011771号