布局


 

什么是布局?

典型情况下,一个网站中所有的页面都有着一致的观感,ASP.NET 2.0 提供了称为“母版页”的技术来帮助基于 .aspx 的页面解决这个问题。Razor 使用称为“布局”的技术来解决同样的问题。这样你可以定义一个公共的站点模板,然后在整个网站中继承它的观感。

在 Razor 中使用布局

没有使用布局的页面如下所示:

控制器的源码如下所示:

Razor 视图中的源码如下所示:

目前还没有使用布局,所以,程序员不得不在每一个页面中复制同样的观感。

 

使用布局进行重构

Razor 的布局使得这一切变得简单,首先,我们在  \Views\Shared 文件夹下增加一个公共的布局模板。默认的公共视图和模板都被保存在这个文件夹中。

这个布局文件的内容如下所示:

对于这个文件需要注意以下几点:

  1. 在文件开头的  @inherits  指令不再是必须的。如果你愿意的话,仍然可以保留,例如你希望使用一个自定义的基类。这样使得文件更加易读。
  2. 我们通过调用  @RenderBody()  方法来指示填充的内容。
  3. 在 head 中,我们使用  “@View.Title” 来输出标题。

在网站中,我们通过布局来保持统一的观感。

现在,我们使用这个布局来更新原来的视图。

注意到下面的三个问题:

  1. 不需要使用标记来包围内容,默认情况下,Razor 就会将整个内容作为部分的内容部分,如果在布局中存在多个区域,你仍然可以通过命名的区域来指定区域,这样,Razor 使得 90%的工作变得简单。
  2. 我们通过代码设置了  View.Title  的属性, Index.cshtml  中的代码将在布局之前执行,所以,我们可以通过编程来设置传递给布局的值。这个技术典型地应用在 header 中,例如 meta 中的设置内容。
  3. 我们通过设置 Layout  属性来设置 Index.cshtml   使用的布局。

生成的结果如下:

在上面的代码中,我们通过设置 Layout  属性来设置 Index.cshtml   使用的布局,这样可以工作,但是,每一个页面都将需要重复这些代码。好消息是 Razor 允许我们不在视图中显式设置 Layout,通过为所有的视图定义一个统一的逻辑来完成这个任务。

可以删除设置 Layout 的代码。

在项目的 Views 文件夹下增加一个名为 _ViewStart.cshtml 的文件。

 _ViewStart 用来定义公共的视图代码,例如,为所有的视图定义同样的布局。

这些代码将在每一个视图之前执行。所以,你就不再需要为每一个视图设置布局了。

注意:由于可以在 ViewStart  中写程序,所以,你可以不是简单的设置布局属性。例如,根据用户设备的不同,采用不同的布局模板,这样,视图的灵活性变得大大增强了。

你还可以在控制器和 Action 的过滤器中设置布局。

 

完成之后的例子

完成之后的页面如下:

控制器的内容:

 Index.cshtml  视图的内容

SiteLayout.cshtml 布局的内容

_ViewStart.cshtml 的内容如下:

生成的 HTML 如下:

高级问题:

可以在布局中嵌套布局吗?
在布局中存在多个不连续的区域,在视图文件中可以填充吗?

这两个问题的答案都是可以。

MVC3 布局

1、_layout.cshtml公共模板。使用Html.Partial(“_header”),html.Partial(“_footer”)加载页头页脚,使用RenderBody加载内容。

2、
1、带有Render的方法返回值是void,在方法内部进行输出;不带的返回值类型为MvcHtmlString,所以只能这样使用:

@Html.Partial 对应 @{Html.RenderPartial(....);} @Html.Action 对应 @{Html.RenderAction(....);}

2、Html.Partial可以直接提供用户控件名作为参数,而Html.Action需要有对应的Action,在Action内部返回PartailResult(即retun PartialView())。 3、对于简单的没有任何逻辑的用户控件,推荐使用Html.Partial;对于需要设置一些Model的用户控件,推荐使用Html.Action。当然,有Model数据也是可以使用Html.Partial方法的,可以看方法的重载。 4、使用Html.Action有个好处,就是可以根据不同的场景选择不同的用户控件。 比如: @Html.Action("UserInfoControl") 在对应的UserInfoControl这个Action中,在用户未登录的时候,可以retun PartialView("LogOnUserControl");登录后,可以retun PartialView("UserInfoControl");

 

Html.Action和Html.RederAction来创建子视图   http://www.cnblogs.com/guanjie20/archive/2011/01/18/1938362.html

在ASP.NET MVC中,创建视图最典型的方式是调用一个action方法,它使用模型准备视图数据。action方法然后调用控制器的视图方法创建视图。然而,你可能想要调用不同的动作方法创建视图的不同部分。例如,可能你有一页面展现了最新新闻,天气和运动。在那种情况下,用三个动作方法是比较好的,一个动作方法处理新闻,另一个处理天气,还有一个处理运动。那样你可以在不同条件下呈现不同的视图,或者是将复杂的视图分解为小型的,更容易管理的片段。

这个主题描述了如何在创建多个视图分段(子视图)的一个视图(父视图)里调用多个动作方法。

1. 父视图和子视图
父视图是包含了调用返回子视图的动作方法的视图。父视图包含大部分用于呈现页面的HTML。子视图仅包含用于展示视图某部分的必须的标记。

例如,一个子视图创建一个列表,视图可能仅仅包含列表所需要的HTML,像下面的例子:

<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>

所有其它的标记(body, head等等)会在包含在父视图中。

2.调用Action和RenderAction辅助方法用于呈现子视图
ASP.NET MVC提供 HTML辅助方法(扩展方法)呈现大多数的 HTML元素,例如表单和链接,那种简化了例如像输入验证这样的公共任务。用于呈现子视图的两个 HTML辅助方法分别是:Aciton和RenderAction。这两个HTML辅助方法都在ChildActionExtensions类中。

Action方法以字符串的形式返回子视图,可以直接被呈现。RenderAction方法在适当的地方呈现子视图。
例如,假设你有一个名为ChildList 的子视图,它包含了上一切显示的HTML代码。控制器包含了下面的动作方法,用于呈现子视图:

public ActionResult ChildList()
{
    return View();
}

注意在控制器中,没有特定的方法呈现父视图或子视图。你呈现一个父视图,父视力再依次呈现它需要的子视图。
为了调用动作方法在父视图中呈现子视图,你可以像下面的示例一样使用Action辅助方法或RenderAction辅助方法。

// One alternative (renders a string)
<%= Html.Action("ChildList") %>

//Another alternative (renders in place)
<% Html.RenderAction("ChildList"); %>

注意因为Html.Action辅助方法返回字符串,必须要等号"="。

3.为辅助方法传递参数
你可以在父视图的不同位置调用相同的动作方法,通过参数传递决定要呈现什么。Action和 RenderAction两个方法都有方法重载接受一个包含了一对参数名和值的对象。下面的代码示例了RenderAction方法调用展示动作方法。在这种情况下,它传递一个包含在这部分呈现的子视图的名称值的匿名对象。标记呈现了一个“新闻”片段,接着是一个“天气”片段。

<% Html.RenderAction("Display", new { section = "News" }); %>
<% Html.RenderAction("Display", new { section = "Weather" }); %>

呈现动作方法看起来可能像下面的例子:

public ActionResult Display(string section)
{
    return View(section);
}

4.从其它控制器或区域调用动作方法
你可以调用不是当前控制器中的动作方法。要实现这样,你调用RenderAction的一个重载方法,指定动作方法和控制器的名称。下面的示例展示了调用SectionController类中的动作方法。第一个参数(字符串)是动作方法的名称,第二个参数(也是字符串)是控制器的名称。

<% Html.RenderAction("Display", "Section"); %>

如果你需要的动作方法在其它的区域中,你可以在对象中传递区域名称,如下:

<% Html.RenderAction("Display", new { area = "Navigation" }); %>

通过使用RenderAction不同的重载方法,你就可以在不同的区域调用不同的控制器。 


ASP.NET MVC 3 带来了一个新的名为 Razor 的视图引擎,同时也支持已经存在的 .aspx 视图引擎。

Section、Partial View 和 Child Action


概括的讲,View中的内容可以分为静态和动态两部分。静态内容一般是html元素,而动态内容指的是在应用程序运行的时候动态创建的内容。给View添加动态内容的方式可归纳为下面几种:

  • Inline code,小的代码片段,如 if 和 foreach 语句。
  • Html helper方法,用来生成单个或多个HTML元素,如view model、ViewBag等。
  • Section,在指定的位置插入创建好的一部分内容。
  • Partial view,存在于一个单独的视图文件中,作为子内容可在多个视图中共享。
  • Child action,相当于一个包含了业务逻辑的UI组件。当使用child action时,它调用 controller 中的 action 来返回一个view,并将结果插入到输出流中。

这个分类不是绝对的。前两种很简单,在前面的文章中也使用过。本文主要介绍后三种方式的应用。

本文目录

Section

Razor视图引擎支持将View中的一部分内容分离出来,以便在需要的地方重复利用,减少了代码的冗余。下面来演示如何使用Section。

创建一个MVC应用程序,选择基本模板。添加一个HomeController,编辑生成的Index方法如下:

public ActionResult Index() {
    string[] names = { "Apple", "Orange", "Pear" };
    return View(names);
} 

右击Index方法,添加视图,编辑该视图如下:

复制代码
@model string[] 
 
@{ 
    ViewBag.Title = "Index"; 
} 
 
@section Header { 
    <div class="view"> 
        @foreach (string str in new [] {"Home", "List", "Edit"}) { 
            @Html.ActionLink(str, str, null, new { style = "margin: 5px" })   
        } 
    </div> 
}

<div class="view"> 
    This is a list of fruit names: 
    @foreach (string name in Model) { 
        <span><b>@name</b></span> 
    } 
</div>

@section Footer { 
    <div class="view"> 
        This is the footer 
    </div> 
} 
复制代码

我们通过@section标签加section的名称来定义一个Section,这里创建了两个section:Header 和 Footer,习惯上一般把section放在View文件的开头或结尾以方便阅读。下面我们在 /Views/Shared/_Layout.cshtml 文件中来使用它们。

编辑 /Views/Shared/_Layout.cshtml 文件如下:

复制代码
<!DOCTYPE html> 
<html> 
<head> 
    <meta charset="utf-8" /> 
    <meta name="viewport" content="width=device-width" /> 
    <style type="text/css"> 
        div.layout { background-color: lightgray;} 
        div.view { border: thin solid black; margin: 10px 0;} 
    </style> 
    <title>@ViewBag.Title</title> 
</head> 
<body>
    @RenderSection("Header") 
 
    <div class="layout"> 
        This is part of the layout 
    </div> 
 
    @RenderBody() 
 
    <div class="layout"> 
        This is part of the layout 
    </div>

    @RenderSection("Footer")
<div class="layout"> 
        This is part of the layout 
    </div> 
</body> 
</html> 
复制代码

我们通过 @RenderSection 方法来调用section的内容,参数指定了section的名称。运行程序后可以看到如下结果:

注意,section只能在当前View或它的Layout中被调用。@RenderSection方法没有找到参数指定的section会抛异常,如果不确定section是否存在,则需要指定第二个参数的值为false,如下:

... 
@RenderSection("scripts", false) 
... 

我们还可以通过 IsSectionDefined 方法来判断一个section是否被定义或在当前View中是否能调用得到,如:

复制代码
... 
@if (IsSectionDefined("Footer")) { 
    @RenderSection("Footer") 
} else { 
    <h4>This is the default footer</h4>    
} 
...
复制代码

Partial View

Partial view(分部视图)是将部分 Razor 和 Html 标签放在一个独立的视图文件中,以便在不同的地方重复利用。接下来介绍如何使用 partial view。

我们先来创建一个partial view 。在 /Views/Shared 目录下新建一个名为 MyPartial 的视图文件,勾选“创建为分部视图”,如下:

添加好的 partial view 文件是一个空文件,我们在这个文件中添加如下代码:

<div>
    This is the message from the partial view.
    @Html.ActionLink("This is a link to the Index action", "Index")
</div> 

这个 MyPartial.cshtml 视图用将创建一个回到首页的连接。当然这里的 @Html.ActionLink 方法也是一种(Html helper)动态加载View内容的方式。

然后在 HomeController 中添加一个List action方法,如下:

public ActionResult List()
{
    return View();
}

继续为此添加一个 List.cshtml 视图,并通过@Html.Partial方法来调用我们要呈现的分部视图,如下:

@{
    ViewBag.Title = "List";
    Layout = null;
}
<h3>This is the /Views/Home/List.cshtml View</h3>
@Html.Partial("MyPartial")

视图引擎将按照规定的顺序先后在 /Views/Home 和 /Views/Shared 文件夹下查找 MyPartial 视图。

运行程序导航到 /Home/List,我们可以看到如下效果:

Partial view 和普通和 View 的使用没有什么区别,也可以使用强类型,如我们在 MyPartial.cshtml 中通过 @model 指定 model 的类型:

复制代码
@model IEnumerable<string>

<div>
    This is the message from the partial view.
    @Html.ActionLink("This is a link to the Index action", "Index")
    
    <ul>
        @foreach (string str in Model)
        {
            <li>@str</li>
        }
    </ul>
</div> 
复制代码

并修改调用 MyPartial.cshtml 视图的主视图 List.cshtml 如下:

@{
    ViewBag.Title = "List";
    Layout = null;
}
<h3>This is the /Views/Home/List.cshtml View</h3>
@Html.Partial("MyPartial", new[] { "Apple", "Orange", "Pear" })

和上面不同的是,这里我们给 @Html.Partial 指定了第二个参数,将一个数组传递给了 MyPartial.cshtml 的 model 对象。运行效果如下:

Child Action

Child action 和 Patial view 类似,也是在应用程序的不同地方可以重复利用相同的子内容。不同的是,它是通过调用 controller 中的 action 方法来呈现子内容的,并且一般包含了业务的处理。任何 action 都可以作为子 action 。接下来介绍如何使用它。

在 HomeController 中添加一个 action,如下:

[ChildActionOnly]
public ActionResult Time()
{
    return PartialView(DateTime.Now);
}

这个 action 通过调用 PartialView 方法来返回一个 partial view。ChildActionOnly 特性保证了该 action 只能作为子action被调用(不是必须的)。

接着我们继续为这个action添加一个相应的 Time.cshtml 视图,代码如下:

@model DateTime

<p>The time is: @Model.ToShortTimeString()</p> 

在 List.cshtml 视图中添加如下代码来调用 Time action 方法 :

...
@Html.Action("Time")

运行结果如下:

我们通过 @Html.Action 方法来调用了 Time action 方法来呈现子内容。在这个方法中我们只传了一个action名称参数,MVC将根据当前View所在Controller去查找这个action。如果是调用其它 controller 中的 action 方法,则需要在第二个参数中指定 controller 的名称,如下:

... 
@Html.Action("Time", "MyController") 

该方法也可以给 action 方法的参数传值,如对于下面带有参数的 action:

... 
[ChildActionOnly] 
public ActionResult Time(DateTime time) { 
    return PartialView(time); 
}

我们可以这样使用 @Html.Action 方法:

... 
@Html.Action("Time", new { time = DateTime.Now })


1.母版页
SiteLayout.cshtml:
<body>
<div id="main-content">
@RenderBody()    //占位符
</div>
</body>

2.子页
@{
    Layout="~/View/Shared/SiteLayout.cshtml";
    View.Title="The Index!";
}
<p>This is the main content!</p>
3.最后输出结果
<div id="main-content"> <p>This is the main content!</p> </div>



SiteLayout.cshtml:
<body>
<div id="main-content">
@RenderBody()    //占位符
</div>
<footer>                  
@if(IsSectionDefined("Footer")){   //如果没有定义就输出 <span>内容
@RanderSection("Footer")        //定义一个"Footer"节
}else{
<span>This is the default footer.</span>
}
</footer>
</body>


@{
    Layout="~/View/Shared/SiteLayout.cshtml";
    View.Title="The Index!";
}
<p>This is the main content!</p>  //@RenderBody()    占位符
@section Footer{                                //<footer>@RanderSection("Footer")</footer>  定义一个节
    This is the<strong>footer</strong>  
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值