今天我們談到的是ASP.NET MVC 3中有關新的Layout佈局系統,在MVC3當中我們可以利用新的Layout佈局系統來代替掉原來在MVC2當中使用的MasterPage。
AD:
I:回憶MVC2當中MasterPage那些事
大家先看下面的代碼:
- <!------------Begin-------------->
- <!-- Master文件 -->
- <%@ Master Language="C#"
- Inherits="System.Web.Mvc.ViewMasterPage" %>
- Master head
- <asp:ContentPlaceHolder ID="MainContent" runat="server" />
- Master1...
- <asp:ContentPlaceHolder ID="OtherContent" runat="server" />
- Master2...
- <asp:ContentPlaceHolder ID="AnyContent" runat="server" />
- Master3...
- <!-------------End--------------->
- <!------------Begin-------------->
- <!-- 某個View文件 -->
- <%@ Page Language="C#"
- MasterPageFile="~/Views/Shared/Site.Master"
- Inherits="System.Web.Mvc.ViewPage" %>
- <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
- MainContent...
- </asp:Content>
- <asp:Content ID="Content2" ContentPlaceHolderID="OtherContent" runat="server">
- OtherContent...
- </asp:Content>
- <asp:Content ID="Content3" ContentPlaceHolderID="AnyContent" runat="server">
- AnyContent...
- </asp:Content>
- <!-------------End--------------->
- <!------------Begin-------------->
- <!-- 最後傳回給客戶端的文件 -->
- Master head
- MainContent...
- Master1...
- OtherContent...
- Master2...
- AnyContent...
- Master3...
- <!-------------End--------------->
我們可以看到在Master中ContentPlaceHolder服務端控件起到了一個佔位符的作用.最後輸出的,其實是在View當中的Content服務端控件內的內容,接下來開始介紹Layout.
II:ASP.NET MVC3 新的Layout佈局系統
在MVC3當中我們可以利用新的Layout佈局系統來代替掉原來在MVC2當中使用的MasterPage(當然在MVC3當中,如果你是繼續使用ASPX視圖引擎的話,那麼還是可以用回原來的MasterPage,然後~~~~然後~你會和runat=”server”保持着從.NET 1.x到.NET 4.0以來從沒有間斷過的合作關係,可謂緣分呀!).
我們在VS2010 MVC3項目中創建Item時,從創建嚮導中可以看到以下新增的幾個Item
下面進行逐一介紹:
Layout頁:
該傢伙其實就相當於原來的Master文件.爲站點的統一主題界面和減少大部分冗餘的Html,head,body標記曾作出過很大的貢獻.可謂是功不可莫啊!MasterPage他的誕生是在.NET 2.0版本!在服役到.NET4.0版本後出現了一個新成員[Layout]去向他挑戰.MasterPage能否經得起新成員的挑戰呢?這個還是得留各位觀衆做詳細對比吧!
Partial頁:
相當於原來的UserControl.它可以爲你減輕不少需要重複勞動的時間!
View頁:
就是View啦.創建它時.一般都是在不需要使用Layout/MasterPage的時候.
View Page with Layout:
等同於原來的View Content Page.它的功能只是爲了實現原來在Layout/MasterPage下所定義的佔位符.當然在原來的MasterPage中如果你沒有實現原先定義的佔位符<asp:ContentPlaceHolder />,那麼在最終合併輸出的時候MasterPage佔位符<asp:ContentPlaceHolder />那裏就會輸出空.
以上這4個新成員都是可以利用新的Razor視圖引擎進行工作.如果你還沒了解Razor那麼可以參考我的另外一編文章
1.Layout頁基礎:
如果你有使用MasterPage的經驗,你將會記得如下的幾個東西
A:<%@ Master %>
B:<%@ Page %>
C:<asp:ContentPlaceHolder />
D:<asp:Content />
但是在Layout中,以上的這些東西將會消失.(作者不排除有WebPages和WebForms兼容工作的可能性)
取而代之的新功能是:
A.Layout屬性:等同於原來的MasterPageFile屬性.
B.@RenderBody()方法:直接渲染整個View到佔位符處,而不需要原來所使用的<asp:Content />.
C.@RenderPage()方法:渲染指定的頁面到佔位符處.
D.@RenderSection方法:聲明一個佔位符,和原來的<asp:ContentPlaceHolder />功能類似.
E.@section標記:對@RenderSection方法聲明的佔位符進行實現,和原來的<asp:Content />功能類似.
1.1.@RenderBody()方法的使用
首先在~/Views/Shared/下創建一個名爲_MyLayout.cshtml的LayoutPage文件,並將默認的內容替換爲如下:
- <!DOCTYPE html>
- <html>
- <head>
- <title>@ViewBag.Title</title>
- </head>
- <body>
- <div>
- 開始渲染Body<br />
- @RenderBody()
- 渲染Body結束<br />
- </div>
- </body>
- </html>
然後打開在~/Views/Home/Index.cshtml文件並替換爲如下的內容:
- @{
- ViewBag.Title = "首頁";
- }
- <div>
- 這裏就是渲染Body啦.~~不需要寫神馬<asp:Content />,其實因爲RenderBody()不在有歧義.
- </div>
最後輸出截圖爲:
這個與之前MasterPage的代碼量相比之下減少了許多,而更爲簡潔明瞭.
最後別忘記把~/Views/_ViewStart.cshtml中的Layout屬性改爲:
Layout = "~/Views/Shared/_MyLayout.cshtml";喔.
在此,你或許會有疑問了.在_Layout中定義的RenderBody()是Render那個頁啊?
答:其實最後Render頁的歸屬就是Render你所訪問的那個頁,比如你訪問/Home/Index.那麼Render就是Home控制器下的Index.cshtml這個文件, 如果訪問的是/Ohter/SomePage時,那麼Render的是Ohter控制器下的SomePage這個.cshtml!
在這裏可能有的朋友沒有接觸過MVC.在此補個基礎,在默認的路由設置選項下:
- public static void RegisterRoutes(RouteCollection routes)
- {
- routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
- routes.MapRoute(
- "Default", // Route name
- "{controller}/{action}/{id}", // URL with parameters
- new { controller = "Home", action = "Index", id = UrlParameter.Optional }
- // Parameter defaults
- );
- }
請求地址:http://localhost/Home/Index的工作流程爲下圖(這裏沒有考慮Layout):
如果這個RenderBody滿足不了你的業務需求,請放心,在此介紹另外一個Render方式RenderPage().它可以讓你指定要Render的頁.
1.2.@RenderPage()方法的使用
在~/Views/Home/文件夾下新建立一個ViewPage1.cshtml文件,將內容改爲如下:
- <div>
- 這裏是~/Views/Home/ViewPage1.cshtml,老規矩:還是不用寫<asp:Content />
- </div>
並在原來的_MyLayout.cshtml文件中增加幾行代碼變成下面的這個樣子:
- <!DOCTYPE html>
- <html>
- <head>
- <title>@ViewBag.Title</title>
- </head>
- <body>
- <div>
- 開始渲染Body<br />
- @RenderBody()
- 渲染Body結束<br />
- <br />
- 開始渲染其他頁<br />
- @RenderPage("~/Views/Home/ViewPage1.cshtml")
- 渲染其他頁結束<br />
- </div>
- </body>
- </html>
我們來看最終的輸出效果:
在這裏記住:@RenderBody()只能在_Layout.cshtml中使用一次,而@RenderPage()則可以使用多次!
好了在這裏如果還有不明白的朋友們.我下面上個圖說明Render的工作原理
如果想要了解在Layout中如何使用類似於原來MasterPage中的<asp:ContentPlaceHolder /><asp:Content />功能請繼續往下看.
III:在Layout佈局系統中實現類似於原來MasterPage功能的實現方式
好,寫到這裏開始介紹上一章節中沒有介紹完的兩個東西:@RenderSection方法和@section標記
1.@RenderSection()方法等價於<asp:ContentPlaceHolder />,用途爲在Layout中聲明一個佔位符.
操作:在原來的_MyLayout.cshtml文件中更改內容爲如下:
- @{
- //some code
- }
- <!DOCTYPE html>
- <html>
- <head>
- <title>@ViewBag.Title</title>
- </head>
- <body>
- <div>
- 開始渲染Body<br />
- @RenderBody()
- 渲染Body結束<br />
- <br />
- 開始渲染其他頁<br />
- @RenderPage("~/Views/Home/ViewPage1.cshtml")
- 渲染其他頁結束<br />
- <br />
- HOHO,開始學習Section了<br />
- 開始渲染Section<br />
- 聲明方式1(推薦):SectionA:<br />
- @RenderSection("SectionA", false)
- -------<br />
- 聲明方式2:SectionB:<br />
- @{
- if (IsSectionDefined("SectionB"))
- {
- @RenderSection("SectionB")
- }
- }
- -------<br />
- 渲染Sction結束<br />
- </div>
- </body>
- </html>
在~/Views/Home/Index.cshtml中更改爲如下內容:
- @{
- ViewBag.Title = "首頁";
- //
- // some code
- //
- }
- @section SectionA{
- <div>這裏是SectionA:也不需要寫神馬runat="server"啊,有木有</div>
- }
- @section SectionB{
- <div>這裏是SectionB:也不需要寫神馬<asp:Content />啊,有木有</div>
- }
- <div>
- 這裏就是渲染Body啦.~~不需要寫神馬<asp:Content />,其實因爲RenderBody()不在有歧義.
- </div>
最後顯示的頁面效果:
問:爲什麼爲什麼要推薦方式1呢?
答:因爲RenderSection()方法有2個重載.
如果使用第一個只接受一個string類型參數的重載的話.~如果你在具體的View中沒有利用@section來定義實現的話,運行會報錯.所以需要配合另外一個方法IsSectionDefined()來使用,才能防止報錯.
而使用第2個重載就可以利用第二個bool類型的參數指明該Section是否爲必須的.所以可以在使用該RenderSection方法的時候直接利用第二個重載,再把bool參數值設爲false,即使你在具體的View中沒有聲明實現@section,運行起來也一如既往地蛋定,不Show黃頁.
IV:關於前篇文章中有熱心的觀衆朋友們問到如何在Layout(MasterPage)中讀取數據庫並初始化頁面的問題的解答
在這裏只是做個一簡單的示範,新建一個類文件,替換如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Data;
- using System.Data.SqlClient; //在這裏就用ADO.NET方式吧.EF我接觸不久!
- namespace Mvc3Application1
- {
- public class ReaderSQL_Date
- {
- private static readonly string _SQL_CONN_STR = "server=.\\mssqlserver,1433;uid=sa;pwd=yourpwd;database=student;";
- public static IList<StudentEntity> GetAllStudent()
- {
- //這裏僅僅是做演示,生產環境並不這樣寫
- using (SqlConnection conn = new SqlConnection(_SQL_CONN_STR))
- {
- SqlCommand cmd = conn.CreateCommand();
- cmd.CommandType = CommandType.Text;
- cmd.CommandText = "SELECT [Sno],[Sname],[Sage] FROM [dbo].[STUDENT]";
- IList<StudentEntity> result = new List<StudentEntity>();
- conn.Open();
- using (SqlDataReader sdr = cmd.ExecuteReader())
- {
- while (sdr.Read())
- {
- result.Add(new StudentEntity
- {
- S_No = sdr.GetInt32(0),
- S_Name = sdr.GetString(1),
- S_Age = sdr.GetInt32(2)
- });
- }
- }
- //SqlConnection.ClearPool(conn); //可選清理連接池.
- return result;
- }
- }
- }
- public class StudentEntity
- {
- public int S_No { get; set; }
- public string S_Name { get; set; }
- public int S_Age { get; set; }
- }
- }
_MyLayout.cshtml替換如下:
- @{
- IList<Mvc3Application1.StudentEntity> studentEntities = Mvc3Application1.ReaderSQL_Date.GetAllStudent();
- }
- <!DOCTYPE html>
- <html>
- <head>
- <title>@ViewBag.Title</title>
- </head>
- <body>
- <div>
- @{
- <table>
- <tr>
- <th>學號</th>
- <th>姓名</th>
- <th>年齡</th>
- </tr>
- @foreach (Mvc3Application1.StudentEntity item in studentEntities)
- {
- <tr>
- <td>@item.S_No</td>
- <td>@item.S_Name</td>
- <td>@item.S_Age</td>
- </tr>
- }
- </table>
- }
- 開始渲染Body<br />
- @RenderBody()
- 渲染Body結束<br />
- <br />
- 開始渲染其他頁<br />
- @RenderPage("~/Views/Home/ViewPage1.cshtml")
- 渲染其他頁結束<br />
- <br />
- HOHO,開始學習Section了<br />
- 開始渲染Section<br />
- 聲明方式1(推薦):SectionA:<br />
- @RenderSection("SectionA", false)
- -------<br />
- 聲明方式2:SectionB:<br />
- @{
- if (IsSectionDefined("SectionB"))
- {
- @RenderSection("SectionB")
- }
- }
- -------<br />
- 渲染Sction結束<br />
- </div>
- </body>
- </html>
最終顯示:
原文鏈接:http://www.cnblogs.com/highend/archive/2011/04/18/asp_net_mvc3_layout.html