1.1理解视图约定
当创建一个项目模版时,可以注意到,项目以一种非常具体的方式包含了一个结构化的Views目录。在每一个控制器的View文件夹中,每一个操作方法都有一个同名的视图文件与其对应。这就提供了视图与操作方法关联的基础。
public ActionResult Index()
{
return View();
}
视图选择逻辑在/Views/ControllerName目录(这里就是去掉Controller后缀的控制器名)下查找与操作方法同名的视图。此处选择的是/Views/Home/Index.cshtml。
与ASP.NET MVC中的大部分方法一样,这一约定是可以重写的。想让Index操作方法渲染一个不同的视图,可以向其提供一个不同的视图名称,代码如下:
public ActionResult Index()
{
return View("NotIndex");
}
对于上面的编码,操作方法依然在/Views/Home目录中查找视图,但选择的不再是Index.cshtml,而是NotIndex.cshtml。
如果需要制定完全位于不同目录结构中的视图,编码如下:
public ActionResult Index()
{
return View("~/Views/Example/Index.cshtml");
}
1.2 强类型视图
假设需要编写一个显示Album实例列表的视图,一种方法是将专辑添加到ViewBag中,然后在视图中进行迭代。
public ActionResult List()
{
var albums = new List<Album>();
for (int i = ; i < ; i++)
{
albums.Add(new Album { Title = "Product" + i });
}
ViewBag.Albums = albums;
return View();
}
然后,再在视图中迭代显示,如下代码:
<ul>
@foreach (Album a in (ViewBag.Albums as IEnumerable<Album>))
{
<li>@a.Tilte</li>
}
</ul>
注意在枚举之前需要将动态的ViewBag.Albums转换为IEnumerable<Album>类型。为了使代码整洁,可以使用dynamic关键字,但是当访问每个Album对象的属性时,就不能再使用智能感知功能。
1 <ul>
2 @foreach (dynamic p in ViewBag.Albums)
3 {
4 <li>@p.Tilte</li>
5 }
6 </ul>
强类型视图既能获得dynamic的简洁语法,又能获得强类型和编译时检查的好处(比如正确的输入属性和方法名称)。强类型视图允许设置视图的模型类型。因此可以从控制器向视图传递一个在两端都是强类型的模型对象,从而获得智能感知、编译器检查等好处。
在Controller方法中,可以通过向重载的View方法中传递模型实例来指定模型,代码如下:
public ActionResult List()
{
var Musics = new List<MusicModels>();
for (int i = ; i < ; i++)
{
Musics.Add(new MusicModels { MusicName = "MusicName" + i.ToString() });
}
return View(Musics);
}
下一步是告知视图哪种类型的模型正在使用@model声明。但要注意这里需要输入模型类型的完全限定类型名(名称空间和类型名称),如下所示
@model IEnumerable<MvcMusicStore.Models.MusicModels>
<ul>
@foreach(MvcMusicStore.Models.MusicModels music in Model)
<li>@music.SingerName</li>
</ul>
如果不想输入模型类型的完全限定类型名,可使用@using关键字,如下所示
@using MvcMusicStore.Models
@model IEnumerable<MusicModels>
<ul>
@foreach(MusicModels music in Model)
<li>@music.SingerName</li>
</ul>
对于在视图中经常使用的名称空间,好的方法是在Views目录下的web.config文件中声明:
<add namespace="MvcMusicStore.Models">
1.3 理解ViewBag、ViewData和ViewDataDictionary
之前介绍了使用ViewBag从控制器向视图传递信息,然后介绍了传递强类型模型。现实中,这些都是通过ViewDataDictionary传递的。
从技术的角度看,数据从控制器传送到视图是通过一个名为ViewData的ViewDataDictionary(这是一个特殊的字典类)。我们可以使用标准的字典语法设置或读取其中的值:
ViewData["CurrentTime"] = DateTime.Now;
尽管这种语法现在也能用,但是MVC3提供了更简单的语法,可以利用C#4的dynamic关键字。ViewBag是ViewData的动态封装器。这样我们就可以按照下面的方式来设置值:
ViewBag.CurrentTime = DateTime.Now;
ViewBag.CurrentTime和ViewData["CurrentTime"] 起到了等同的作用。
一般来说,大部分代码使用ViewBag,而不是ViewData,这两种语法并不存在技术上的差异,仅仅是因为ViewBag相对于字典语法而言看上去好看。
注意,ViewBag和ViewData的差异:
- 只有当要访问的关键字是一个有效的C#标识符时,ViewBag才起作用。例如,如果在ViewData["Key With Spaces"]中存放一个值,那么就不用使用ViewBag访问,因为无法通过编译。
- 动态值不能作为一个参数传递给扩展方法,因为C#编译器为了选择正确的扩展方法,在编译时必须知道每一个参数的真正类型。
2.视图模型
在操作方法上右击 --> “添加视图”
弹出添加视图页:
- View name:当从一个操作方法的上下文中打开这个对话框时,视图的名称默认被填充为操作方法的名称。视图的名称是必须有的。
- Template:一旦选择一个模型类型,就可以选择一个基架模版。这些模版利用Visual Studio模版系统来生成基于选择模型类型的视图。
- 引用脚本库:这个选项用来指示要创建的视图是否应该包含指向JavaScript库(如果对视图有意义的话)的引用。默认情况下,_Layout.cshtml文件既不引用jQuery Validation库,也不引用Unobtrusive jQuery Validation库,只引用主jQuery库。
当创建一个包含数据条目表单的视图(如Edit视图或者Create视图)时,选择这个选项会添加对jqueryval捆绑的脚本引用。如果要实现客户端验证,那么这些库就是必须的。除这种情况外,完全可以忽略这个复选框。
- 创建一个分部视图:选择这个意味着要创建的视图不是一个完整的视图,因此,Layout选项是不可选用的。生成的部分视图除了在其顶部没有<html>标签和<head>标签外,很像一个常规的视图。
- 使用布局页:这个选项决定了要创建的视图是否引用布局,还是成为一个完全独立的视图。如果选择使用默认的布局,就没必要指定一个布局了,因为在_ViewStart.cshtml文件中已经指定了布局。这个选项是用来重写默认布局文件的。
2.2 Razor视图引擎
ASP.NET MVC中提供了两种不同的视图引擎:较新的Razor视图引擎和较早的WebForms视图引擎。
Razor中的核心转换字符是(@),这个单一字符用作标记-代码的转换字符,有时也反过来用作代码-标记的转换字符。
这里一共有两种基本类型的转换:代码表达式和代码快。
<h1>Listing @items.Length items.</h1>
表达式@items.Length是作为隐式表达式来求解的,然后输出表达式的值3。这里不需要指出代码表达式的结束位置。
但是Razor自动从代码转回标记的能力,也带来了二义性的问题:
@{
string rootNamespace = "MyApp";
}
<span>@rootNamespace.Models</span>
这个示例想要的输出结果是: <span>MyApp.Models</span> ,然而实际会出现错误,提示string没有Models属性,此时需要通过圆括号解决:
1 @{
2 string rootNamespace = "MyApp";
3 }
4 <span>@(rootNamespace).Models</span>
这样可以告诉Razor,.Models是字面量文本,而不是代码表达式的一部分。
对于电子邮件地址时的情况,Razor可以辨别出邮件的模式,进而不处理这种形式的表达式:
<span>support@megacorp.com</span>
但是如果确实想将这种形式的字符串作为一个表达式,也需要合理用圆括号:
对于
<li>Item_@item.Length</li>
期望的输出结果是<li>Item_3</li>,但是Razor会将其按照字符串进行打印。
处理的方法是:
<li>Item_@(item.Length)</li>
有时也需要使用@符号来进行转义:
<p>
You should follow
@@aspnet
</p>
3.Razor语法示例
常见用途下的Razor语法;
- 隐式代码表达式
代码表达式将被计算并将值写入到响应中,这就是视图中显示值的一般原理。
<span>@model.Message</span>
- 显示代码表达式
代码表达式的值将被计算并写入到响应中,这就是在视图中显示值的一般原理
<span>1 + 2 = @(1 +2 )</span>
- 无编码代码表达式
有些情况下,需要显式的渲染一些不应该采用HTML编码的值,这时可以采用Html.Raw方法来保证该值不被编码
<span>@Html.Raw(model.Message)</span>
- 代码块
不像代码表达式先求的表达式的值,然后再输出到响应,代码块是简单地执行代码部分
@{
int x = ;
string y = "because."
}
- 文本和标记相结合
这个例子显示了在Razor中混用文本和标记的概念,具体如下:
@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.
}
第一种使用<text>标签,这样只是把标签内容写入到响应中,而标签本身则不写入。第二种方式使用一种特殊的语法,实现代码到纯文本的转换,但是这种方法每次只能作用于一行文本。
- 转义代码分隔符
可使用“@@”来编码“@”以达到显示“@”的目的。此外,时钟都可以选择使用HTML编码来实现。
Razor:
the asp.net twitter handle is @aspnet
或者
the asp.net twitter handle is @@aspnet
- 代码注释
@*
代码块
*@
4.布局
Razor的布局有助于使应用程序的多个视图保持一致的外观。可以使用布局为网站定义公共模版(或只是其中的一部分)。公公模版包含一个或多个占位符,应用程序中的其他视图为它们提供内容。从某些角度看,布局很像视图的抽象基类。如下则是一个简单的布局:
<!DOCTYPE html>
<html>
<head>
<title>@ViewBag.Title</title>
</head>
<body>
<h1>@ViewBag.Title</h1>
<div id="main-content">@RenderBody()</div>
<footer>@RenderSection("Footer")</footer>
</body>
</html>
对应视图的代码如下:
1 @{
2 Layout = "~Views/Shared/SiteLayout.cshtml";
3 ViewBag.Title = "The Index";
4 }
5
6 <p>this is the main content!</p>
7
8 @section Footer{
9 this is the <strong>footer</strong>.
10 }
@section语法为布局中定义的一个节指定了内容。
默认情况下,视图必须为布局中定义的每一个节提供内容。如果向当前的布局中添加一个新节时,会使得引用该布局的每一个视图都不能正常运行。
但是,RenderSection方法有一个重载版本,允许指定不需要的节。可以给required参数传递一个false值来标记Footer节是可选的。
<footer>@RenderSection("Footer", required: false)</footer>
有时也在视图中定义一些默认内容
<footer>
@if (IsSectionDefined("Footer"))
{
RenderSection("Footer");
}
else
{
<span>this is the default footer</span>
}
</footer>
5.ViewStart
在创建一个默认的ASP.NET MVC项目后,会在Views目录下自动添加一个_ViewStart.cshtml文件,它指定了一个默认布局
@{
Layout = "~/Views/Shared/_Layout.cshtml"
}
如果多个视图都使用都使用同一个布局,就会产生冗余。_ViewStart.cshtml中的代码先于任何视图运行,所以一个视图可以重写Layout属性的默认值,从而重新选择了一个不同的布局。如果一组视图拥有共同的设置,那么_ViewStart.cshtml中的代码可以用来对共同的视图进行统一配置。如果有视图需要覆盖统一的设置,只需要修改对应的属性值即可。
6.指定部分视图
除了返回视图之外,操作方法也可以通过PartialView方法以PartialViewResult的形式返回部分视图:
public class HomeController : HomeController
{
public ActionResult Message()
{
ViewBag.Message = "this is a partial view.";
return PartialView();
}
}
这种情形下,渲染的是视图Message.cshtml,但是如果布局是由_ViewStart.cshtml页面指定(而不是直接在视图中)的,将无法渲染布局。
除了不能指定布局之外,部分视图看起来和正常视图没有分别:
<h2>@ViewBag.Message</h2>
在使用Ajax技术进行更新时,部分视图是很有用的。示例使用jQuery将一个部分视图的内容加载到一个使用了Ajax调用的当前视图中:
<div id="result"></div>
@section scripts{
<script type="text/javascript">
$(function(){
$('#result').load('/home/message');
});
</script>
}
代码使用jQuery的load方法向Message操作方法发出一个Ajax请求,而后使用请求的结果更新id属性值为result的DIV元素。
ASP.NET MVC5高级编程 之 视图的更多相关文章
-
ASP.NET MVC5 高级编程 第3章 视图
参考资料<ASP.NET MVC5 高级编程>第5版 第3章 视图 3.1 视图的作用 视图的职责是向用户提供界面. 不像基于文件的框架,ASP.NET Web Forms 和PHP ,视 ...
-
ASP.NET MVC5 高级编程 第5章 表单和HTML辅助方法
参考资料<ASP.NET MVC5 高级编程>第5版 第5章 表单和HTML辅助方法 5.1 表单的使用 5.1.1 action 和 method 特性 默认情况下,表单发送的是 HTT ...
-
ASP.NET MVC5 高级编程 第2章 控制器
参考资料<ASP.NET MVC5 高级编程>第5版 第2章 控制器 控制器:响应用户的HTTP 请求,并将处理的信息返回给浏览器. 2.1 ASP.NET MVC 简介 MVC 模式中的 ...
-
ASP.NET MVC5 高级编程-学习日记-第一章 入门
1.1 ASP.NET MVC 简介 ASP.NET是一种构建Web应用程序的框架,它将一般的MVC(Model-View-Controller)模式应用于ASP.NET框架. 1.1.1 MVC模式 ...
-
ASP.NET MVC5高级编程 之 模型
1. 为MVC Music Store建模 Models文件夹(右击) --> 添加 --> 类 为类添加对应的属性: public class Album { public virtua ...
-
ASP.NET MVC5 高级编程-学习日记-第三章 视图
开发人员之所以花费大量时间来重点设计控制器和模型对象,是因为在这些领域中,精心编写的整洁代码是开发一个可维护Web应用程序的基础. 3.1 视图的作用 视图的职责是向用户提供用户界面.当控制器针对被请 ...
-
ASP.NET MVC5高级编程 之 Ajax
jQuery不仅支持所有现代浏览器,包括IE.Firefox.Safari.Opera和Chrome等,还可以在编写代码和浏览器API冲突时隐藏不一致性(和错误). 1. jQuery jQuery擅 ...
-
学习《ASP.NET MVC5高级编程》——基架
基架--代码生成的模板.我姑且这么去定义它,在我学习微软向编程之前从未听说过,比如php代码,大部分情况下是我用vim去手写而成,重复使用的代码需要复制粘贴,即使后来我在使用eclipse这样的IDE ...
-
ASP.NET MVC5高级编程 之 HTML辅助方法
Html属性调用HTML辅助方法,Url属性调用URL辅助方法,Ajax属性调用Ajax辅助方法. HTML辅助方法 1.Html.BeginForm @using (Html.BeginForm(& ...
随机推荐
-
Netty In Action
1 introduction 1.2 Asynchronous by design two most common ways to work with or implement an asynchro ...
-
czxt
实验三 进程调度模拟程序 1. 目的和要求 1.1. 实验目的 用高级语言完成一个进程调度程序,以加深对进程的概念及进程调度算法的理解. 1.2. 实验要 ...
-
实现checkbox组件化(Component)
之前我写了一篇自定义checkbox的文章,通过css3实现自定义的checkbox,并没有使用当今流行的Reactjs, 或者Vuejs之类的进行组件化.但是很显然,这样封装的checkbox组件复 ...
-
Latex 笔记
A source file is made up of text, formulas, and instructions (commands) to $\LaTeX.$ Commands start ...
-
scala言语基础学习二
使用yield和函数式编程转化数组 算法案例(移除第一个负数之后的所有负数) 改良高校方案
-
openlayers加载百度地图
最近在做openlayers添加百度地图的扩展类,经过轮番的尝试,终于将其接入了,但是发现偏差比较大,有根据百度的坐标进行了比对,将切片原点进行了调整,发现OK了.打开百度地图,可以看出切片的路径如: ...
-
MIPI D-PHY 总结
Operating Modes: Control, High-Speed, and Escape 1.The Lane is only in High-Speed mode during Data b ...
-
Apache Commons Pool2 源码分析 | Apache Commons Pool2 Source Code Analysis
Apache Commons Pool实现了对象池的功能.定义了对象的生成.销毁.激活.钝化等操作及其状态转换,并提供几个默认的对象池实现.在讲述其实现原理前,先提一下其中有几个重要的对象: Pool ...
-
linux下64位汇编的系统调用(5)
看到这里大家都基本知道了如何进行linux下的汇编系统调用:不过有些童鞋可能会问:那些C库中函数里为我们解决的额外汇编代码你是怎么知道的? 好吧,我承认:我是通过逆向知道的,这貌似有点犯规的嫌疑- 比 ...
-
GIT 数据结构
Git doesn’t think of or store its data this way. Instead, Git thinks of its data more like a series ...