zoukankan      html  css  js  c++  java
  • ASP.NET MVC3 系列教程 – 新的Layout布局系统

    I:回忆MVC2当中MasterPage那些事

    code:

    <!------------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
    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.@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啦.~~不需要写神马&lt;asp:Content /&gt;,其实因为RenderBody()不在有歧义.
    </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.在此补个基础,在默认的路由设置选项下:

    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):
    image

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

    1.2.@RenderPage()方法的使用

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

    <div>
        这里是~/Views/Home/ViewPage1.cshtml,老规矩:还是不用写&lt;asp:Content /&gt;
    </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>
    

    我们来看最终的输出效果:
    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>
    

    在~/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>
    

    最后显示的页面效果:
    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 { 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>
    
    

    最终显示:
    image

    本文到此结束!
    在此谢谢各位关注本系列教程和关注博主的朋友们!有大家的[推荐]我会有动力将这个系列一直写下去!

  • 相关阅读:
    C# 不用添加WebService引用,调用WebService方法
    贪心 & 动态规划
    trie树 讲解 (转载)
    poj 2151 Check the difficulty of problems (检查问题的难度)
    poj 2513 Colored Sticks 彩色棒
    poj1442 Black Box 栈和优先队列
    啦啦啦
    poj 1265 Area(pick定理)
    poj 2418 Hardwood Species (trie树)
    poj 1836 Alignment 排队
  • 原文地址:https://www.cnblogs.com/highend/p/asp_net_mvc3_layout.html
Copyright © 2011-2022 走看看