热门:网页模板.net视频教程JQueryMVCjsonExtJs源码示例三级联动JQuery菜单
您现在的位置:.Net中文社区>> .Net编程>>正文内容

ASP.NET MVC3 新的Layout布局系统

发布时间:2011年04月26日点击数: 佚名

I:回忆MVC2当中MasterPage那些事

code:

  1. <!------------Begin--------------> 
  2. <!-- Master文件 --> 
  3. <%@ Master Language="C#"  
  4.     Inherits="System.Web.Mvc.ViewMasterPage" %> 
  5. Master head 
  6. <asp:ContentPlaceHolder ID="MainContent" runat="server" /> 
  7. Master1... 
  8. <asp:ContentPlaceHolder ID="OtherContent" runat="server" /> 
  9. Master2... 
  10. <asp:ContentPlaceHolder ID="AnyContent" runat="server" /> 
  11. Master3... 
  12. <!-------------End---------------> 
  13.  
  14.  
  15. <!------------Begin--------------> 
  16. <!-- 某个View文件 --> 
  17. <%@ Page Language="C#"  
  18.     MasterPageFile="~/Views/Shared/Site.Master"  
  19.     Inherits="System.Web.Mvc.ViewPage" %> 
  20. <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server"> 
  21. MainContent... 
  22. </asp:Content> 
  23.  
  24. <asp:Content ID="Content2" ContentPlaceHolderID="OtherContent" runat="server"> 
  25. OtherContent... 
  26. </asp:Content> 
  27.  
  28. <asp:Content ID="Content3" ContentPlaceHolderID="AnyContent" runat="server"> 
  29. AnyContent... 
  30. </asp:Content> 
  31. <!-------------End---------------> 
  32.  
  33.  
  34. <!------------Begin--------------> 
  35. <!-- 最后传回给客户端的文件 --> 
  36. Master head 
  37. MainContent... 
  38. Master1... 
  39. OtherContent... 
  40. Master2... 
  41. AnyContent... 
  42. Master3... 
  43. <!-------------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

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文件,并将默认的内容替换为如下:

  1. <!DOCTYPE html> 
  2.  
  3. <html> 
  4. <head> 
  5.     <title>@ViewBag.Title</title> 
  6. </head> 
  7. <body> 
  8.     <div> 
  9.         开始渲染Body<br /> 
  10.         @RenderBody() 
  11.         渲染Body结束<br /> 
  12.     </div> 
  13. </body> 
  14. </html> 

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

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

最后输出截图为:
 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.在此补个基础,在默认的路由设置选项下:

  1. public static void RegisterRoutes(RouteCollection routes) 
  2.     routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
  3.  
  4.     routes.MapRoute( 
  5.         "Default"// Route name 
  6.         "{controller}/{action}/{id}"// URL with parameters 
  7.         new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults 
  8.     ); 
  9.  

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

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

1.2.@RenderPage()方法的使用

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

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

并在原来的_MyLayout.cshtml文件中增加几行代码变成下面的这个样子:

  1. <!DOCTYPE html> 
  2.  
  3. <html> 
  4. <head> 
  5.     <title>@ViewBag.Title</title> 
  6. </head> 
  7. <body> 
  8.     <div> 
  9.         开始渲染Body<br /> 
  10.         @RenderBody() 
  11.         渲染Body结束<br /> 
  12.         <br /> 
  13.         开始渲染其他页<br /> 
  14.         @RenderPage("~/Views/Home/ViewPage1.cshtml") 
  15.         渲染其他页结束<br /> 
  16.          
  17.     </div> 
  18. </body> 
  19. </html> 

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

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文件中更改内容为如下:

  1. @{ 
  2.     //some code 
  3. <!DOCTYPE html> 
  4.  
  5. <html> 
  6. <head> 
  7.     <title>@ViewBag.Title</title> 
  8. </head> 
  9. <body> 
  10.     <div> 
  11.         开始渲染Body<br /> 
  12.         @RenderBody() 
  13.         渲染Body结束<br /> 
  14.         <br /> 
  15.         开始渲染其他页<br /> 
  16.         @RenderPage("~/Views/Home/ViewPage1.cshtml") 
  17.         渲染其他页结束<br /> 
  18.         <br /> 
  19.         HOHO,开始学习Section了<br /> 
  20.         开始渲染Section<br /> 
  21.         声明方式1(推荐):SectionA:<br /> 
  22.         @RenderSection("SectionA", false) 
  23.         -------<br /> 
  24.          
  25.         声明方式2:SectionB:<br /> 
  26.         @{ 
  27.             if (IsSectionDefined("SectionB")) 
  28.             { 
  29.                 @RenderSection("SectionB") 
  30.             } 
  31.         } 
  32.         -------<br /> 
  33.         渲染Sction结束<br /> 
  34.     </div> 
  35. </body> 
  36. </html> 

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

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

最后显示的页面效果:image

image


问:为什么为什么要推荐方式1呢?
答:因为RenderSection()方法有2个重载.

如果使用第一个只接受一个string类型参数的重载的话.~如果你在具体的View中没有利用@section来定义实现的话,运行会报错.所以需要配合另外一个方法IsSectionDefined()来使用,才能防止报错.

而使用第2个重载就可以利用第二个bool类型的参数指明该Section是否为必须的.所以可以在使用该RenderSection方法的时候直 接利用第二个重载,再把bool参数值设为false,即使你在具体的View中没有声明实现@section,运行起来也一如既往地蛋定,不Show黄 页.

IV:关于前篇文章中有热心的观众朋友们问到如何在Layout(MasterPage)中读取数据库并初始化页面的问题的解答

在这里只是做个一简单的示范,新建一个类文件,替换如下:

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Web; 
  5. using System.Data; 
  6. using System.Data.SqlClient; //在这里就用ADO.NET方式吧.EF我接触不久! 
  7.  
  8. namespace Mvc3Application1 
  9.     public class ReaderSQL_Date 
  10.     { 
  11.         private static readonly string _SQL_CONN_STR = "server=.\\mssqlserver,1433;uid=sa;pwd=yourpwd;database=student;"
  12.  
  13.         public static IList<StudentEntity> GetAllStudent() 
  14.         { 
  15.             //这里仅仅是做演示,生产环境并不这样写 
  16.             using (SqlConnection conn = new SqlConnection(_SQL_CONN_STR)) 
  17.             { 
  18.                 SqlCommand cmd = conn.CreateCommand(); 
  19.                 cmd.CommandType = CommandType.Text; 
  20.                 cmd.CommandText = "SELECT [Sno],[Sname],[Sage] FROM [dbo].[STUDENT]"
  21.  
  22.                 IList<StudentEntity> result = new List<StudentEntity>(); 
  23.                 conn.Open(); 
  24.                 using (SqlDataReader sdr = cmd.ExecuteReader()) 
  25.                 { 
  26.                     while (sdr.Read()) 
  27.                     { 
  28.                         result.Add(new StudentEntity 
  29.                         { 
  30.                             S_No = sdr.GetInt32(0), 
  31.                             S_Name = sdr.GetString(1), 
  32.                             S_Age = sdr.GetInt32(2) 
  33.                         }); 
  34.                     } 
  35.                 } 
  36.                 //SqlConnection.ClearPool(conn); //可选清理连接池. 
  37.  
  38.                 return result; 
  39.             } 
  40.         } 
  41.     } 
  42.  
  43.     public class StudentEntity 
  44.     { 
  45.         public int S_No { get; set; } 
  46.         public string S_Name { get; set; } 
  47.         public int S_Age { get; set; } 
  48.     } 

_MyLayout.cshtml替换如下:

  1. @{ 
  2.     IList<Mvc3Application1.StudentEntity> studentEntities = Mvc3Application1.ReaderSQL_Date.GetAllStudent(); 
  3. <!DOCTYPE html> 
  4.  
  5. <html> 
  6. <head> 
  7.     <title>@ViewBag.Title</title> 
  8. </head> 
  9. <body> 
  10.     <div> 
  11.  
  12.         @{ 
  13.             <table> 
  14.                 <tr> 
  15.                     <th>学号</th> 
  16.                     <th>姓名</th> 
  17.                     <th>年龄</th> 
  18.                 </tr> 
  19.                 @foreach (Mvc3Application1.StudentEntity item in studentEntities) 
  20.                 { 
  21.                     <tr> 
  22.                         <td>@item.S_No</td> 
  23.                         <td>@item.S_Name</td> 
  24.                         <td>@item.S_Age</td> 
  25.                     </tr> 
  26.                 } 
  27.             </table> 
  28.         } 
  29.  
  30.         开始渲染Body<br /> 
  31.         @RenderBody() 
  32.         渲染Body结束<br /> 
  33.         <br /> 
  34.         开始渲染其他页<br /> 
  35.         @RenderPage("~/Views/Home/ViewPage1.cshtml") 
  36.         渲染其他页结束<br /> 
  37.         <br /> 
  38.         HOHO,开始学习Section了<br /> 
  39.         开始渲染Section<br /> 
  40.         声明方式1(推荐):SectionA:<br /> 
  41.         @RenderSection("SectionA", false) 
  42.         -------<br /> 
  43.          
  44.         声明方式2:SectionB:<br /> 
  45.         @{ 
  46.             if (IsSectionDefined("SectionB")) 
  47.             { 
  48.                 @RenderSection("SectionB") 
  49.             } 
  50.         } 
  51.         -------<br /> 
  52.         渲染Sction结束<br /> 
  53.     </div> 
  54. </body> 
  55. </html> 

最终显示:

image

本文到此结束!

本站热点业务

更多模板/案例展示

关于我们 | 联系我们 | 团队日志 | 网站地图 | 网站合作