ASP.NET MVC - 视图 (视图、ViewBag、ViewData、Razor、PartialView、ViewStart、@Render、@RenderSection)
关键字:视图、ViewBag、ViewData、Razor、PartialView、ViewStart、@Render、@RenderSection
- 视图的作用
- 指定视图
- 强类型视图
- 理解试图模型
- 如何添加视图
- Razor的用法
- 指定部分视图
视图的作用
视图的职责是向用户提供用户界面。当提供对模型的引用后,视图会把模型转换为准备反馈给用户的格式。在ASP.NET MVC中,完成这一过程由两部分操作,其中一个是检查有控制器提交的模型对象,另一个是将其内容转换为HTML格式。



不像基于文件的Web框架,比如ASP.NET Web Forms和PHP,视图本身不会被直接访问,浏览器不能直接指向一个视图并渲染它。相反,视图总是被控制器渲染,因为控制器为它提供了要渲染的数据。
指定视图
按照约定,每一个控制器在Views目录下都有一个对应的文件夹,其名称与控制器一样,指示没有Controller后缀名。
在每一个控制器的View文件夹中,每一个操作方法都有一个同名的视图文件与其相对应。这就提供了视图与操作方法关联的基础。例如,操作方法通过View方法返回ViewResult对象。

注意,这个控制器操作没有指定视图的名称。当不指定视图名称时,操作方法返回的ViewResult对象将按照约定来确定视图。它会在目录/Views/ControllerName下查找与action名称相同的视图。上面的情况下选择的视图便是/Views/Home/Contact.cshtml。
与ASP.NET MVC中的大部分约定设置一样,这一约定是可以重写的。如果想让Contact方法渲染一个不同的视图,可以向其提供一个不同的视图名称。

这样编码后,索然操作方法仍然在/View/Home目录中查找视图,但选择的不再是Contact.cshtml,而是NotContact.cshtml。然而,在其他一些应用中,我们可能需要指定完全位于不同目录结构中的视图。针对这种情况,我们可以使用带有~符号的语法来提供视图的路径。

注意,为了在查找视图时避开视图引擎的内部查找机制,在使用这种语法时,必须提供视图的文件扩展名。
ViewData和ViewBag
数据从控制器传送到视图是通过一个名为ViewData的ViewDataDictionary(这是一个特殊的字典类)。
ViewBag是ViewData的动态封装器。大多数情况下,ViewData和ViewBag之间并不存在真正的技术差异。ViewBag相对于字典语法而言仅仅是一种更受开发人员欢迎的语法而已。
ViewData["CurrentTime"] = DateTime.Now;
//等同于
ViewBag.CurrentTime = DateTime.Now;
虽然两者之间并不存在真正的技术优势,但是两者之间的一些关键差异还是需要知道的
一个很明显的差异就是,只有当要访问的关键字是一个有效的C#标识符时,ViewBag才起作用。

另一个需要知道的重要差异是,动态值不能作为一个参数传递给扩展方法。因为C#编译器为了选择正确的扩展方法,在编译时必须知道每个参数的真正类型。

强类型视图
在Controller方法中,可以通过向重载的View方法中传递模型实例来制定模型。
public ActionResult Index()
{
var genres = storeDB.Genres.ToList();
return View(genres);
}
在后台,首先把传给View方法的值赋给ViewData.Model属性。然后告知视图哪种类型的模型正在使用@model声明。注意这里需要输入模型类型的完全限定类型名。
@model IEnumerable<MvcMusicStore.Models.Genre>
@{
ViewBag.Title = "Store";
}
<h3>Browse Genres</h3>
<p>
Select from @Model.Count() genres:</p>
<ul>
@foreach (var genre in Model)
{
<li>@Html.ActionLink(genre.Name, "Browse", new { genre = genre.Name })</li>
}
</ul>
如果不像输入模型类型的完全限定类型名,可以使用@using关键字声明。
@using MvcMusicStore.Models
@model Genre
对于在视图中经常使用的命名空间,一个较好的方法就是在Views目录下的web.config文件中声明。
<system.web.webPages.razor>
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="MvcMusicStore.Models"/>
</namespaces>
</pages>
</system.web.webPages.razor>
视图模型
视图通常需要显示各种没有直接映射到域模型的数据。例如,可能需要视图来显示单个商品的详细信息。有时在同一仕途上也需要显示商品附带的其他信息,比如当前登录系统的用户名、该用户是否有权编辑商品等。把与视图主模型无关的数据存放在ViewBag属性中,可以很容易地实现这些数据在视图中的显示,而且也为在视图中显示数据提供了一个灵活的方法。
但这本非适用与每个人。如果要严格控制流入视图的数据,就必须使所有数据都是强类型数据,以便视图编写人员能够利用智能感知功能。可能采用的一个方法是编写自定义的“视图特定模型”。这里的模型可以看成仅限于向视图提供信息的模型。
添加视图
Visual Sutido中的ASP.NET MVC工具的Add View对话框使得创建视图非常容易。
在需要添加视图的方法体内点击右键即可。


Razor视图引擎
Introduction to ASP.NET Web Programming Using the Razor Syntax (C#)
代码表达式
Razor中的核心转换字符是 @ 符号。这个单一字符用作标记-代码的转换字符,有时也反过来用作代码-标记的转换字符。这里共有两种基本类型的转换:代码表达式和代码块。求出表达式的值,然后将值写入到响应中。
// 表达式@Model.Length是作为隐式代码表达式求解的,
// 然后在输出中显示表达式的值。需要注意的一点是,
// 这里不需要指出代码表达式的结束位置。
<h1>Listing @Model.Length items.</h1>
// Web Forms视图只支持显示代码表达式,
// 这样上面的代码段将是如下形式
<h1>Listing <%: Model.Length %> items.</h1>
HTML编码
代码块
// Razor语法
@foreach (var item in Model)
{
<li>The item name is @item.</li>
}
// Web Forms语法
<% foreach(var item in Model)
{%>
<li>The item name is <%: item %>.</li>
<%}%>
多行代码块
@{
string s = "One line of code.";
ViewBag.Title "Another line of code.";
}
Razor语法示例
隐式代码表达式
@*Razor语法*@
<span>@Model.Length</span>
<!--Web Forms 语法-->
<span><%: Model.Length %></span>
显式代码表达式
@*Razor语法*@
<span>ISBN@(isbn)</span>
<!--Web Forms 语法-->
<span>ISBN<%: isbn %></span>
无编码代码表达式
@*Razor语法*@
<span>@Html.Raw(Model.Message)</span>
<!--Web Forms 语法-->
<span><%: Html.Raw(Model.Length) %></span>
代码块
@*Razor语法*@
@{
int x = 123;
string y = string.Empty;
}
<!--Web Forms 语法-->
<%
int x = 123;
string y = string.Empty;
%>
文本标记相结合
@*Razor语法*@
@foreach (var item in items)
{
<span>Item @item.Name.</span>
}
<!--Web Forms 语法-->
<% foreach(var item in items) { %>
<span>Item <%: item.Name %>.</span>
<% } %>
混合代码和纯文本
@*Razor语法*@
@if (showMessage)
{
<text>This is plain text.</text>
}
@*或者*@
@if (showMessage)
{
@:This is plain text.
}
<!--Web Forms 语法-->
<% if(showMessage) { %>
This is plain text.
<% } %>
转义代码分隔符
@*Razor语法*@
My Twitter Handler is @hacked
@*或者*@
My Twitter Handler is @@hacked
<!--Web Forms 语法-->
<%expression %> marks a code nugget.
服务器端的注释
@*Razor语法*@
@*This is a multiline server side comment.
@if(showMessage){
<h1>@ViewBag.Message</h1>
}
All of this is commented out.
*@
<!--Web Forms 语法-->
<%--
This is a multiline server side comment.
<% if(showMessage) { %>
<h1><%: ViewBag.Message %></h1>
<% } %>
All of this is commented out.
--%>
调用泛型方法
@*Razor语法*@
@(Html.SomeMethod<AType>())
<!--Web Forms 语法-->
<%: Html.SomeMethod<AType>() %>
布局
Razor的布局有助于使应用程序中的多个视图保持一致的外观。与Web Forms中的母版页的作用是相同的,但是布局提供了更加简洁的语法和更大的灵活性。
<div id="main">
@RenderBody()
</div>
@RenderBody是一个占位符,用来标记使用这个布局的视图将渲染它们的主要内容的位置。
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
上面的这个视图通过Layout属性来制定布局。当渲染这个视图时,它的HTML内容将被放在_Layout.cshtml中的id属性值为main的DIV元素中。
@section语法为布局中定义的一个节指定内容。
<footer>@RenderSection("Footer")</footer>
@section Footer{
This is the <strong>footer</strong>.
}
通过使用RenderSection的重载版本,允许指定不需要的节。可以给required参数传递一个false值来标记scripts节是可选的。
@RenderSection("scripts", required: false)
ViewStart
如果多个视图使用同一个布局,就会产生冗余,并且很难维护。
_ViewStart.cshtml页面可以用来消除这种冗余。
当创建一个默认的ASP.NET MVC项目时,在Views目录下会自动添加一个_ViewStart.cshtml文件,它指定了一个默认布局。

@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
因为这个代码先于任何视图运行,所以一个视图可以重写Layout属性的默认值,从而重新选择一个不同的布局。如果一组视图拥有共同的设置,那么_ViewStart.cshtml文件就有了用武之地,因为我们可以在它里面对共同的视图配置进行统一设置。如果有视图需要覆盖统一的设置,我们只需修改对应的属性即可。
指定部分视图
除了返回视图之外,操作方法也可以通过PartialView方法以PartialViewResult的形式返回部分视图。
public ActionResult GenreMenu()
{
var genres = storeDB.Genres.ToList();
return PartialView(genres);
}
这种情况下,渲染的视图是GenreMenu.cshtml,但是如果布局是由_ViewStart.cshtml页面制定的,将无法渲染布局。
当使用Ajax技术进行部分更新时,部分视图是很有用的。下面展示了一个非常简单的例子,使用jQuery将一部分视图的内容加载到一个使用了Ajax调用的当前视图中:
<div id="result"></div>
<script type="text/javascript">
$(function()){
$('#result').load('/store/genremenu');
});
</script>
前面的代码使用jQuery的load方法向Message操作方法发出一个Ajax请求,而后使用请求的结果更新id属性值为result的DIV元素。
摘录自:[美]Jon Galloway,Phil Haack,Brad Wilson等著,孙远帅,邹权译 ASP.NET MVC 4高级编程(第4版) [Professional ASP.NET MVC 4] [M]、清华大学出版社,2013、43-65、

浙公网安备 33010602011771号