實現自己的MasterPage和WebPart控制項
開發沒有aspx,ascx的web程式,全部由自訂控制項產生,並且支援MasterPage摸版功能。
asp.net提供的MasterPage確實是一個好的功能,我也很需要這樣的東西,可是我想更多的擴充一下,以實現自己的MasterPage控制項。需要支援可以動態更改title,動態添加關鍵字,動態添加css, 動態添加script。這是個不錯的想法,如何??
那麼我們回到asp.net伺服器控制項的架構上來,先來熟悉下它,理解它的生命週期,這個很重要,我可不開玩笑,因為我需要對它加以利用,動點小手術,因此你必須必須理解它,否則,請放下鍵盤,拿起你的吉他,一邊玩兒^_*。
在你放下鍵盤那起吉他之前,請把我這篇文章看完,好了,在這裡我只談2.0的相關部分。
===================控制項生命週期開始===================
控制項構造器
初始化階段 Init事件
-----載入檢視狀態
-----載入回傳資料
載入階段 Load事件
-----引發資料修改事件
-----引發回傳事件
預產生階段 PreRender
儲存檢視狀態
產生階段
卸載階段 Unload
釋放
===================控制項生命週期結束===================
以上的東西寫的文章已經很多了,我只憑記憶把他寫出來,不對的地方,大家指正。
還有一個需要熟悉的東西就是控制項的渲染流程,你需要理解他,不管怎樣,你都要理解他,請暫時放下你的吉他,理解它,真的,實在太重要了。
Control控制項暴露了一個公用的RenderControl(HtmlTextWrite write)方法,用與產生html到輸出資料流。
這個方法是這麼定義的,這裡我說的是2.0。
RenderControl(HtmlTextWrite write)
{
if(可視)
{
繼續Render(write);
}
}
看到了,如果當前控制項的Visible屬性設定為true的話,它才會調用Render方法,注意這個方法是受保護的,不是由你來調用的,不過你還是有機會調用他的,放心,繼續看下面。
除非你繼承Control控制項,否則你只能近接的調用他,也就是由Page架構或是Control的RenderControl方法調用它。
Render方法是這樣的:
Render(HtmlTextWrite write)
{
繼續RenderChildren(write);
}
看上去是去產生子控制項,確實如此,RenderChildren是這樣的:
RenderChildren(HtmlTextWrite write)
{
foreach(Control control in Controls)
{
RenderControl(write); //這裡我近接的調用了Render方法,雖然你是受到保護的。可我還是調用啦
}
}
看到了,RenderChildren裡面有回去了,原來Control控制項的渲染流程是這樣的啊,通過判斷自己的Contros屬性來不斷的調用,只到自己的所有子控制項都調用到,好傢夥。
以上提到的是寫web伺服器控制項的必備知識,很基礎,但是你不可以小視他,一點要過他,你才會寫出好的控制項來。
web開發的底層就是一堆的HTML標籤,無論是jsp還是asp.net都是對html某種方式的封裝,是HTML的產物,IE瀏覽器訪問web伺服器,最終我們接收到的還是html文本。IE然後通過渲染引擎解釋這些標籤,在螢幕上展現出來可見的效果。
asp.net提供了很多伺服器控制項,提供了很多所見即所得 (WYSIWYG)的功能,豐富了web應用程式的開發。
這些伺服器控制項架構,有些地方我們是可以利用的,就是說我們自己可以來擴充,寫出符合自己需求的控制項來。asp.net web Control帶有太多的樣式屬性,比如說Panel控制項,就有如Color,Width等各種屬性,因為它繼承於WebControl控制項。如果你需要這麼一個Panel類似的控制項 ,可是你有不需要那些從WebControl繼承而來的屬性,那麼好的選擇就是你直接繼承Control控制項,這個控制項只有基本的控制項架構,而沒有那些可見的web樣式屬性。
恰好我需要這樣的控制項,因為我不需要那些可見的web樣式屬性,因為我要產生的控制項通過CSS檔案來控制的,也就是所有的空間都只輸出Div這個標籤。如果這樣的標籤:
<div id="id" class="class">
<div id="id_children" class="class_container">
<ul><li></li></ul>
</div>
<div id="id_children" class="class_container"> </div>
</div>
如上,標籤時可以嵌套的。
到這裡開始自己動手,建立自己的MasterPage控制項,因為我不需要樣式控制,所以我選擇繼承Control控制項,以便於利用他的架構模型和渲染模型。
public class MasterControl : Control
{
#region //欄位
protected string id;
protected string title;
protected string keyword;
protected List<string> css;
protected List<string> script;
protected Page page;
#endregion
//略去N行代碼...
#region //重寫基類方法
protected override void Render(HtmlTextWriter writer){....}
#endregion
#region //私人方法
private void GenericHeadHTML(HtmlTextWriter writer)
{
writer.AddAttribute("http-equiv", "Content-Type");
writer.AddAttribute(HtmlTextWriterAttribute.Content, "text/html; charset=utf-8");
writer.RenderBeginTag(HtmlTextWriterTag.Meta);
writer.RenderEndTag();
writer.WriteLine();
writer.AddAttribute("http-equiv", "Content-Language");
writer.AddAttribute(HtmlTextWriterAttribute.Content, "zh-CN");
writer.RenderBeginTag(HtmlTextWriterTag.Meta);
writer.RenderEndTag();
writer.WriteLine();
writer.AddAttribute(HtmlTextWriterAttribute.Name, "keywords");
writer.AddAttribute(HtmlTextWriterAttribute.Content, keyword);
writer.RenderBeginTag(HtmlTextWriterTag.Meta);
writer.RenderEndTag();
writer.WriteLine();
writer.RenderBeginTag(HtmlTextWriterTag.Title);
writer.Write(title.Remove(title.Length - 3));
writer.RenderEndTag();
writer.WriteLine();
foreach (string itemCss in css)
{
writer.AddAttribute(HtmlTextWriterAttribute.Rel, "stylesheet");
writer.AddAttribute(HtmlTextWriterAttribute.Href, itemCss);
writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/css");
writer.AddAttribute("media", "all");
writer.RenderBeginTag(HtmlTextWriterTag.Link);
writer.RenderEndTag();
writer.WriteLine();
}
foreach (string itemScript in script)
{
writer.WriteLine("<script type=\"text/javascript\" src=\"" + itemScript +"\" ></script>");
}
}
#endregion
}
namespace MINGMING.MUSIC.Contorls
{
public class MasterPage : MasterControl
{
#region //欄位
protected ControlContainerBase headerLayout, contentLayout, footerLayout;
#endregion
#region //構造方法
public MasterPage(Page page)
: base(page)
{
headerLayout = new FooterLayout(this);
contentLayout = new ContentLayout(this);
footerLayout = new HeaderLayout(this);
}
#endregion
}
}
頁面調用測試:
#region 欄位
protected RequestContext requestContext; //web組件需要的請求上下文
protected NewsPartZone news1, news2, news3, news4; //web組件
protected MasterControl masterPage; //MasterPage模板控制項
#endregion
#region //重寫基類方法
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
requestContext = new RequestContext();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Initialize(); //初始化
}
#endregion
#region //初始化
private void Initialize()
{
#region
/*
NewsEntity newsEntity = new NewsEntity();
NewsCategoryEntity newsCategoryEntity = new NewsCategoryEntity();
List<NewsEntity> newsList ;
List<NewsCategoryEntity> newsCategorys ;
int totalRecord;
newsEntity.ID = 3;
newsEntity.Title = "testTitle88888";
newsEntity.Content = "testContent88888";
newsEntity.Author = "liuming";
newsEntity.ImageFilename = null;
newsEntity.HTMLFilename = "888880100.html";
newsEntity.Category.ID = 1;
newsEntity.Template.ID = 1;
newsBLL.Add(newsEntity);
newsCategorys = newsCategoryBLL.GetAll();
newsList = newsBLL.GetPage(1, true, 1, 10, out totalRecord);
*/
#endregion
masterPage = new MasterPage(this); //自訂的MasterPage控制項,為當前頁設定MasterPage
masterPage.ID = "layout"; //頁面ID
masterPage.Title = "test Title"; //頁面標題
masterPage.Keyword = "key1,key2,key3"; //頁面關鍵字
masterPage.Css.Add("/Resources/Css/main.css"); //當前頁面所需要的樣式表檔案
masterPage.Script.Add("/Resources/Script/main.js"); //當前頁面所需要的指令檔
requestContext.PageHit.PageIndex = 1; //組件需要的請求上下文
requestContext.PageHit.PageSize = 2;
news1 = new NewsPartZone(); //組件1
news1.ID = "news_partzone"; //組件1 ID
news1.IsShowHeader = true; //是否顯示組件的Header地區
news1.Title = "組件1"; //Header地區的文字
news1.Parent = masterPage.Controls[1] as ControlContainerBase; //組件的父容器
news1.RequestContext = requestContext; //請求上下文
news1.MasterPage = masterPage; //組件的MasterPage
news1.Initialize(); //將所有子控制項加到控制項樹,然後將自己加到MasterPage裡面,也就是把自己加到Parent屬性所指向的對象
requestContext.PageHit.PageIndex = 1;
requestContext.PageHit.PageSize = 3;
news2 = new NewsPartZone(); //組件2
news2.ID = "news_partzone2";
news2.Title = "組件2"; //這個title不會顯示出來
news2.Parent = masterPage.Controls[1] as ControlContainerBase;
news2.RequestContext = requestContext;
news2.MasterPage = masterPage;
news2.Initialize();
news3 = new NewsPartZone(); //組件3
news3.ID = "news_partzone3";
news3.IsShowHeader = true;
news3.Title = "組件3";
news3.Parent = masterPage.Controls[1] as ControlContainerBase;
news3.RequestContext = requestContext;
news3.MasterPage = masterPage;
news3.Initialize();
requestContext.PageHit.PageIndex = 1;
requestContext.PageHit.PageSize = 4;
news4 = new NewsPartZone(); //組件4
news4.ID = "news_partzone3";
news4.Title = "組件3"; //這個title不會顯示出來
news4.Parent = masterPage.Controls[2] as ControlContainerBase;
news4.RequestContext = requestContext;
news4.MasterPage = masterPage;
news4.Initialize();
}
#endregion
最終產生的網頁代碼如下:
下面的這個HTML標籤全部由程式產生,所有的字元,包括頭部地區的。都是從伺服器端動態產生出來的。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="zh-CN" />
<meta name="keywords" content="key1,key2,key3" />
<title>
test Title - this.owner.MasterPage.Title - this.owner.MasterPage.Title - this.owner.MasterPage.Title - this.owner.MasterPage.Title
</title>
<link rel="stylesheet" href="/Resources/Css/main.css" type="text/css" media="all" />
<link rel="stylesheet" href="/Resources/Css/newsList.css" type="text/css" media="all" />
<link rel="stylesheet" href="/Resources/Css/newsList.css" type="text/css" media="all" />
<link rel="stylesheet" href="/Resources/Css/newsList.css" type="text/css" media="all" />
<link rel="stylesheet" href="/Resources/Css/newsList.css" type="text/css" media="all" />
<script type="text/javascript" src="/Resources/Script/main.js" ></script>
<script type="text/javascript" src="/Resources/Script/news.js" ></script>
<script type="text/javascript" src="/Resources/Script/news.js" ></script>
<script type="text/javascript" src="/Resources/Script/news.js" ></script>
<script type="text/javascript" src="/Resources/Script/news.js" ></script>
</head>
<body>
<div id="layout">
<div id="layout_footer">
Page_Header - 這裡是頁頭
</div>
<div id="layout_content">
<div id="news_partzone" class="partzone">
<div id="news_partzone_header" class="partzone_header">
組件1
</div>
<div id="news_partzone_content" class="partzone_content">
<div id="news_list_container">
<ul><li>網路歌曲“黑色巧克力“ 07 - 顏繪唐</li><li>網路歌曲“黑色巧克力“ 06 - 顏繪唐</li></ul>
</div>
<div id="page_hit">
</div>
</div>
</div><div id="news_partzone2" class="partzone">
<div id="news_partzone2_content" class="partzone_content">
<div id="news_list_container">
<ul><li>網路歌曲“黑色巧克力“ 07 - 顏繪唐</li><li>網路歌曲“黑色巧克力“ 06 - 顏繪唐</li><li>網路歌曲“黑色巧克力“ 05 - 顏繪唐</li></ul>
</div>
<div id="page_hit">
</div>
</div>
</div><div id="news_partzone3" class="partzone">
<div id="news_partzone3_header" class="partzone_header">
組件3
</div>
<div id="news_partzone3_content" class="partzone_content">
<div id="news_list_container">
<ul><li>網路歌曲“黑色巧克力“ 07 - 顏繪唐</li><li>網路歌曲“黑色巧克力“ 06 - 顏繪唐</li><li>網路歌曲“黑色巧克力“ 05 - 顏繪唐</li></ul>
</div>
<div id="page_hit">
</div>
</div>
</div>
</div>
<div id="layout_header">
Page_Footer - 這裡是頁尾<div id="news_partzone3" class="partzone">
<div id="news_partzone3_content" class="partzone_content">
<div id="news_list_container">
<ul><li>網路歌曲“黑色巧克力“ 07 - 顏繪唐</li><li>網路歌曲“黑色巧克力“ 06 - 顏繪唐</li><li>網路歌曲“黑色巧克力“ 05 - 顏繪唐</li><li>網路歌曲“黑色巧克力“ 04 - 顏繪唐</li></ul>
</div>
<div id="page_hit">
</div>
</div>
</div>
</div>
</div>
</body>
</html>
附圖片: