[注:此文对应Chapter 3:Views]
一、View的功能:
1.View用来呈现页面UI,通过Controller来指定View:
要注意的是,MVC和以前基于文件的Web应用不同,URL指向的并不是最终显示UI的文件,
在MVC中,和URL打交道的是Controller,而不是View,是通过Controller中的Action Method来指定要显示的View
2.Controller中指定View的规则:
在Controller中返回值类型为ActionResult的Action Method可以指定一个用来显示UI的View,
返回视图的代码:return View([参数]);
返回View的View方法有三种不同参数,对应不同需求:
1)参数为空:return View()
这种为最常用的格式,用来返回和Action方法名同名的默认视图;
2)参数为视图文件名:return View("HelloWorld.cshtml")
使用这种格式,可以将Action方法Url指向View/ControllName/HelloWorld.cshtml
即,可以将Action方法Url指向View/ControllName下,和Action不同名的View文件
3)参数为任意位置视图文件:return View("视图相对路径")
在这种格式下,可以将Action方法对应的Url指向任意视图文件
Controller代码:
public class HomeController : Controller
{
public ActionResult Sample()
{
ViewBag.Message = "Hello World, this is a Sample!";
return View("~/Views/Shared/Error.cshtml");
}
}
上面的代码中,HomeController的Action方法Sample(), 将Url: 域名/home/sample 指向了项目自动生成的Error视图
运行程序得到的效果(注意地址):
二、ViewData和ViewBag
1.ViewData
原则上,controller中的数据是通过ViewDataDictionary(字典类)类的对象ViewData来传递给View
如:ViewData["CurrentTime"] = DataTime.Now;
2.ViewBag
从MVC3开始,将上面的语法进行简化,使用ViewBag动态包装ViewData,允许我们使用下面的语法:
ViewBag.CurrentTime = DataTime.Now
这种写法和上面的字典模式完全相同。
注意:
1)如果ViewBag.关键词其中的关键字中有空格,则不能编译通过;
2)ViewBag不能直接作为动态参数进行传值
如: @Html.TextBox("name",ViewBag.Name)——错误!
@Html.TextBox("name",ViewData["Nmae"]) —— 正确!
@Html.TextBox("name",(string)ViewBag.Name)——正确!
三、基于强类型的View(Strongly Typed Views)
1.原理:
ViewData是ViewDataDictionary对象,该类不同于普通Dictionary类,其中包含了一个Model property,允许
从Controller中,将一个(只能是一个)指定对象传到View中。
这种方式不同于使用ViewBag,是强类型。不需要再进行类型指定,直接就可以使用该对象的属性和方法。
2.使用:
1)将要传到View中的对象作为参数给View()方法:
如:return View(albums);
2)在View中,用model接收该对象,直接包含新型信息,不需要再进行类型指定。
@model IEnumerable<Album>
<ul>
@foreach(Album a in Model)
{ <li>@a.Title</li>}
</ul>
3.在View中添加命名空间引用
1)直接在.cshtml文件中添加
@using MvcMusicStore.Models
2)在Views文件夹的web.config文件中添加,对整个Views文件夹中所有View都有效
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
。。。。
<add namespace="MvcMusicStore.Models" />
</namespaces>
</pages>
4.通过NuGet获取书籍配套例程代码:
建好一个MVC4项目,【工具】——【库程序包管理器】——【程序包管理控制台】
在命令行中键入:Install-Package Wrox.ProMvc4.Views.AlbumList
这将添加两个文件夹到项目中,Album类和AlbumController在\Samples\AlbumList中,视图文件Albums.cshtml在\View\Albums中
对应的URL为:域名/albums/listweaklytyped和域名/albums/liststronglytyped
分别非强类型和强类型方式访问,可以通过代码比较其区别
四、View Models
1.起因——Conroller默认只能传递一个强类型对象到View中:
1)ViewData所继承的ViewDataDictrionary类中,只能包含一个Model类,所以,每次只能从Controlller传到View一个对象。
2)View中,大多数情况下需要多个后台传过来的对象来进行绑定显示或操作,单个后台穿过来的类对象不够用,而使用ViewBag
的话,又失去了强类型的好处。
2.解决方案:View Modles
写自定义的View modle class,将你需要的所有信息都包含其中。
如:自定义一个购物车Modle类
public class ShoppingCartViewModle
{
public IEnumerable<Product> Products {get;set;}
public decimal CartTotal {get; set;}
public string Message {get;set;}
}
这样,就可以把你需要的所有相关购物车的所有信息综合在一起传递给View,并且使用的强类型View方式
@model ShoppingCartViewModel
接收到的就是从Controller传过来的完整信息。
3. 例子:
建好一个MVC4项目,【工具】——【库程序包管理器】——【程序包管理控制台】
在命令行中键入:Install-Package Wrox.ProMvc4.Views.ViewModel
执行成功后,同上面的例子,会在项目中增加两个文件夹:
/Samples/ShoppingCartViewModel 包含Product类、ShoppingCartViewModel类和控制器ShoppingCartController类
/Views/ShoppingCart/ 包含对应的视图Index.cshtml
运行后的效果(域名/ShoppingCart)
五、Razor View Engine
简单的介绍跳过去,直接写核心的
1. 代码表达方式
最重要的标示符在Razor中就是“@”
1)代码表达式
如 :@对象名.属性 ,等同于Web Form视图中的<%: 对象名.属性 %>
*注:
虽然Razor比较智能,能够判断大多数情况,自动判定到底是想要转换后台代码,还是直接显示,
但也会遇到混淆的时候,可以通过下面几种方式来避免:
A) @(后台代码)
通过给后台代码加(),来强制将@要转换的内容,和其后面要直接显示的文本分开。
B) @@将显示为@文本
2)HTML编码(Html Encoding)
为防止注入攻击,Razor表达式会自动进行HTML编码
@{string message = "<script>alert('haacked!');</script>";}
<span>@message</span>
上面的HMTL View代码在运行时会被解释为:
<span><script>alert('haacked!');</script></span>
这种HTML编码是自动进行的。
在某些情况下,需要取消HTML编码,可以使用HtmlHelp,使用HtmlStirng对象或者Html.Raw()
如:
@{string message = "<strong>This is bold!</strong>";}
<span>@Html.Raw(message)</span>
这次,就不会再被转码,会直接显示为:
<span><strong>This is bold!</strong></span>
另外,使用@Ajax.JavaScriptStringEncode来编码和Javascript相关的用户输入,来防止注入攻击,如:
<script type="text/javascript">
$(function () {
var message = 'Hello @Ajax.JavaScriptStringEncode(ViewBag.Username)';
$("#message").html(message).show('slow');
});
</script>
3)代码段:
@{代码段}
2. Razor 语法:
1)隐式代码表达式:
<span>@model.Message</span>
又Razor自动判断后面的.Message是text文本还是model的property
2)显示代码表达式:
<span>@(model).Message</span>
在括号中的是后台代码,其外的是文本
3)不经Html转码的表达式:
<span>@Html.Raw(model.Message)</span>
前面提过,Razor为防止注入攻击,自动对用户输入进行HTML转码,如果特殊情况下不用转码,需要写成上面的格式
4)代码段:
@{
int x = 123;
string y = "hello!";
}
5)混合文本和标签
@foreach(var item in items)
{
<span> Item @item.Name.</span>
}
6)混合代码和文本
@if(showMessage)
{
<text>This is plain text </text>
}
或
@if(showMessage)
{
@:This is plain text.
}
注意,后面的语法@:只能针对一行代码
7)显示文本的@
@ 或者 @@
8)服务器端注释:
@*
This is a multiline server side comment.
@if (showMessage) {
<h1>@ViewBag.Message</h1>
}
All of this is commented out.
*@
9)调用泛型函数(Generic Method)
@(Html.SomeMethod<AType>())
其实和显式的Razor代码表达式一样,注意外面加()!
3. Layouts 布局
类似于Asp.net中的MasterPage(母板页),用来设定统一外观的。
设定整体布局使用的是~/_ViewStart.cshtml,它会在所有View被加载之前加载,指定母版布局视图
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
每个View下Controller对应的文件夹中,可以添加自己的_ViewStart.cshtml,用来指定独自使用的布局视图,采取就近原则(替View代根目录中的);
而且,Layout框架的赋值语句:Layout="。。。",也可以加到任意一个View文件中,作为此文件的单独布局框架。
1)@RenderBody()
Layout Template View中的@RenderBody()用于占位。
2)@RenderSection()
一个Layout可以包含多个分块(setions),例如,可以为Layout添加Footer分块
<footer>@RenderSection("Footer")</footer>
在使用这个Layout的View中,需要加入@section Footer{..}代码,来设置自己的footer,如:
@section Footer{ @@Copyright 2001-2015, All Right Received. }
但是,大多数时候,希望section都是可选的,可将其改为:
<footer>@RenderSection("Footer", required: flase) </footer>
更为通用的方式,是在设置可更改的Section时,配备一个默认的Section外观:
<footer>
@if (IsSctionDefined("Footer"))
{
RenderSection("Footer");
}
else
{
<span>This is the default footer. </span>
}
</footer>
六、Patial View
部分View是不包含layout的局部View。
通常用来作为配合Ajax进行局部刷新。
例子:
Install-Package Wrox.ProMvc4.Views.SpecifyingViews