详解ASP.NET MVC 3新的Layout布局系统

开发 后端
今天我们谈到的是ASP.NET MVC 3中有关新的Layout布局系统,在MVC3当中我们可以利用新的Layout布局系统来代替掉原来在MVC2当中使用的MasterPage。

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---------------> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.

我们可以看到在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

image

下面进行逐一介绍:

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> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

然后打开在~/Views/Home/Index.cshtml文件并替换为如下的内容:

@{  
    ViewBag.Title = "首页";  
}  
 
<div> 
    这里就是渲染Body啦.~~不需要写神马&lt;asp:Content /&gt;,其实因为RenderBody()不在有歧义.  
</div> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

***输出截图为:
image

这个与之前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  
    );  
 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

请求地址:http://localhost/Home/Index的工作流程为下图(这里没有考虑Layout):

image

如果这个RenderBody满足不了你的业务需求,请放心,在此介绍另外一个Render方式RenderPage().它可以让你指定要Render的页.

1.2.@RenderPage()方法的使用

在~/Views/Home/文件夹下新建立一个ViewPage1.cshtml文件,将内容改为如下:

<div> 
    这里是~/Views/Home/ViewPage1.cshtml,老规矩:还是不用写&lt;asp:Content /&gt; 
</div> 
  • 1.
  • 2.
  • 3.

并在原来的_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> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

我们来看最终的输出效果:

image

在这里记住:@RenderBody()只能在_Layout.cshtml中使用一次,而@RenderPage()则可以使用多次!

好了在这里如果还有不明白的朋友们.我下面上个图说明Render的工作原理

image

如果想要了解在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> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.

在~/Views/Home/Index.cshtml中更改为如下内容:

@{  
    ViewBag.Title = "首页";     
    //  
    // some code  
    //  
}  
@section SectionA{  
    <div>这里是SectionA:也不需要写神马runat="server"啊,有木有</div> 
}  
@section SectionB{  
    <div>这里是SectionB:也不需要写神马&lt;asp:Content /&gt啊,有木有</div> 
}  
<div> 
    这里就是渲染Body啦.~~不需要写神马&lt;asp:Content /&gt;,其实因为RenderBody()不在有歧义.  
</div> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

***显示的页面效果:

image


image

问:为什么为什么要推荐方式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 { getset; }  
        public string S_Name { getset; }  
        public int S_Age { getset; }  
    }  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.

_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> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.

最终显示:

image 

原文链接:http://www.cnblogs.com/highend/archive/2011/04/18/asp_net_mvc3_layout.html

【编辑推荐】

  1. 浅谈ASP.NET MVC 3中如何使用Model
  2. 体验ASP.NET MVC 3中的Razor特性
  3. MVC架构模式为什么这样“红”?
  4. 专访微软MVP衣明志:走进ASP.NET MVC 2框架开发
  5. ASP.NET MVC 3基础教程之Web Pages
责任编辑:彭凡 来源: 博客园
相关推荐

2010-10-12 09:52:02

ASP.NET MVC

2010-10-08 14:32:32

ASP.NET MVCNuPack

2011-01-15 23:07:59

2011-04-14 09:19:22

ASP.NET MVC

2010-03-19 09:17:16

ASP.NET MVC

2010-09-15 09:18:21

ASP.NET MVC

2009-09-10 09:50:47

ASP.NET MVC

2009-10-29 09:15:32

ASP.NET MVCDropDownLis

2009-09-18 10:20:26

PRG数据验证

2009-07-24 13:20:44

MVC框架ASP.NET

2012-03-31 10:01:40

ASP.NET MVC

2009-07-31 12:43:59

ASP.NET MVC

2010-08-16 09:14:37

ASP.NET MVC

2010-02-03 09:50:58

ASP.NET MVC

2009-07-24 11:55:29

ASP.NET MVC

2010-10-20 09:05:16

ASP.NET MVC

2010-12-07 09:38:15

ASP.NET MVC

2009-07-22 10:34:37

ActionInvokASP.NET MVC

2009-07-20 15:44:32

ASP.NET MVC

2009-07-22 09:11:02

Action方法ASP.NET MVC
点赞
收藏

51CTO技术栈公众号