我的MVC之旅(3)--------MVC Music Store 第三篇 Views and ViewModels [翻译]

 前言

  有网友说不要浪费时间了赶紧干点正事,也有人觉得还不错;我个人觉得看懂是一回事,但是能够写出来分享是另一回事,这样记忆深刻有助于加深自己的理解,而且可以帮助有些和我一样的初学者,遇到的问题,怎么解决等等.

好了,下面开始正题.上周做完第二篇控制器之后,接下来就是第三篇 视图和模型了,源文章链接:http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-3

概述

本章通过简单的几个示例,介绍视图的使用方法以及控制器和视图之间的数据传递方法,简单而且直观,并且简单介绍了生成页面链接的方法.

内容

 先来回顾一下:我们之前已经使用控制器返回String 类型的字符,这很好的让我们了解了控制器的工作原理,但是这不是真正的web应用程序.

我们想要一个更简单的方式返回HTML内容到浏览器--模版文件可以轻松地自定义HTML内容并发回浏览器,这就是视图.

1.添加第一个视图:

要应用视图,首先要改变HomeController 控制器的 Index方法的返回值为ActionResult,并且我们让他返回一个View();代码如下:

1  
2         //
3         // GET: /Home/
4 
5         public ActionResult Index()
6         {
7             return View();
8         }

上面的代码表示,我们想使用视图得到一个结果返回.

我们现在添加一个视图 到我们的项目里面,光标定位到Index()方法,右键单击选择添加视图:

 

  添加视图对话框允许我们快速方便地生成视图文件,默认情况下,添加视图对话框已经为我们光标定位的控制器方法添加好了名称,我们不需要修改什么,直接点击确定,就会添加一个试图文件到工程目录:Views/Home/Index.cshtml.

视图文件的名字和目录非常重要,使用Mvc默认的命名规则,目录/View/Home 对应HomeController,文件Index.cshtml对应控制器方法:Index(). 使用这种命名规则,我们不用在Index()方法中显示指定视图文件,而是直接  return View().就像上面的HomeController.Index(),它将会自动引用View/Home/Index.cshtml.

添加完视图之后,默认会打开该视图文件,默认代码如下:

1 @{
2     ViewBag.Title = "Index";
3 }
4 
5 <h2>Index</h2>

该视图文件使用 Razor 语法 ,这比Asp.net Web Forms 中的 Web Forms视图引擎和上一版本的Asp.net mvc 更简洁.当然 WebForms视图引擎在Asp.net 3.0中仍然可用,但是很多开发者觉得Razor更加适用于Asp.net Mvc 开发.

  前三行代码设置页面标题ViewBag.Title.我们等一下将看看它是怎么工作的,现在我们改一下页面的代码:

1 @{
2     ViewBag.Title = "Index";
3 }
4 
5 <h2>This is the Home Page</h2>

接下来运行程序看一下主页,会看到我们已经更新的文本:

现在,我们已经为HomeController.Index添加了视图Index.cshtml,并且运行了出来。下面我们即将看一下Mvc给我们提供的统一网站部局文件.

2.使用统一布局文件

很多网站的网页有一些全站公用的东西:导航,页脚,LOGO,CSS文件等.Razor 让我们很轻松地管理这些东西,使用_Layout.cshtml,工程已经为我们建立此文件,位于:/Views/Shared/_Layout.cshtml.

我们看一下布局文件:

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <meta charset="utf-8" />
 5     <title>@ViewBag.Title</title>
 6     <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
 7     <script src="@Url.Content("~/Scripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
 8     <script src="@Url.Content("~/Scripts/modernizr-2.5.3.js")" type="text/javascript"></script>
 9 </head>
10 
11 <body>
12     @RenderBody()
13 </body>
14 </html>

  很简单,仅包含一些CSS和常规脚本.我们的视图文件将会通过 @RenderBody()命令来展示,其他的公共内容都可以在这里添加,我们想让我们的MuvMusicStore用一个公共的页眉,上面包含首页链接和商店链接,所以,我们在@RenderBody()命令上面添加一些代码(黄色高亮部分),个人觉得这里和母版差不多.

添加完之后,先不要运行 

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <meta charset="utf-8" />
 5     <title>@ViewBag.Title</title>
 6     <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
 7     <script src="@Url.Content("~/Scripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
 8     <script src="@Url.Content("~/Scripts/modernizr-2.5.3.js")" type="text/javascript"></script>
 9 </head>
10 
11 <body>
12     <div id="header">
13         <h1>ASP.NET MVC MUSIC STORE</h1>
14         <ul id="navlist">
15             <li class="first"><href="/"
16                 id="current">Home</a></li>
17             <li><a
18                 href="/Store/">Store</a></li>
19         </ul>
20     </div>
21     @RenderBody()
22 </body>
23 </html>

空项目模版进包含一些基本的css用于显示验证消息,本项目设计师添加了一些常用的Css和一些图片来控制我们的应用程序的外观,我们需要把这些文件同时添加进项目里(可以去这里下载)

下载完成解压之后,打开相关文件包,选择我们需要的文件添加到项目里:

 现在,我们重新生成并刷新首页:

 

是不是很熟悉:这就是母版.

  简单回顾一下:

    • HomeCongroller.Index引用并展示/Views/Home/Index.cshtml ,尽管我们并没有显示指定视图文件地址而只是使用return View();但是因为我们使用Mvc默认命名规则,所以,这样并不会导致找不到文件.
    • 首页通过视图文件展示一个简单的欢迎信息.
    • 使用统一布局文件,让欢迎信息显示于全局统一风格的页面中。

 

3.使用模型传递数据到视图

只有html代码的静态页面不能满足我们的应用程序要求,我们需要的是一个能够和用户沟通的动态网站,我们需要把数据从控制器传递到视图文件.

在Model-view-controller模式里,Model表示 应用程序中的数据.Model一般对应数据库中的表,但这不是必须的.

返回一个ActionResult的控制器可以传递一个Model到视图,控制器可以打包所有需要的数据,生成输出并传递到目标视图文件用来得到Html输出给浏览器,这很简单,让我们看看怎么做.

首先我们需要建立一些Model类:Genres(流派),Albums(相册).右击/Models/文件夹,选择添加/类,命名为:Genre.cs,确定之后编辑器会打开Genre.cs文件,我们添加公共属性Name

 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Web;
 6 
 7 namespace MvcMusicStore.Models
 8 {
 9     public class Genre
10     {
11         public string Name { getset; }
12     }
13 } 

  相同步骤创建Album.cs,有一个Title属性和  Genre属性:

 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Web;
 6 
 7 namespace MvcMusicStore.Models
 8 {
 9     public class Album
10     {
11         public string Title { getset; }
12         public Genre Genre { getset; }
13     }
14 }

现在,我们可以修改StoreController 使用视图从模型显示动态信息,我们给Albums一个和Request ID相同的名字(演示起见).

首先:打开StoreController.cs,修改Details 方法,让它显示一个相册的信息,引入MuvMusicStore.Models命名空间以便于使用相关模型类,修改Detail的返回值类型:string to ActionResult,修改方法逻辑:返回一个Album对象给View(稍后我们会讲如何从数据库检索数据), 但是现在我们将使用“模拟数据”.

给Details添加视图文件,不过这个步骤要复杂一点点,在添加视图对话框里我们要勾选“创建强类型视图” 然后在下面选择 Album (MvcMusicStore.Models),如果下拉框里面没有选项,请重新生成项目后重试,支持模版就用Empty ,勾选 引用脚本库,点击确定我们会看到生成的视图文件如下:

2 @model MvcMusicStore.Models.Album
3 
4 @{
5     ViewBag.Title = "Details";
6 }
7 
8 <h2>Details</h2>

比我们刚才添加的HomeController.Index的视图多了第一行:它表明这个视图强制关联到 Album class,Razor引擎会识别传进来的Album对象,所以我们可以在视图编辑器中轻松访问 模型属性,并且写代码时候能够自动感应.

更新<h2>标签内容:

 2 @model MvcMusicStore.Models.Album
 3 
 4 @{
 5     ViewBag.Title = "Details";
 6 }
 7 
 8 <h2>Album: @Model.Title</h2>
 9 

当你输入 @Model 之后,智能感知便会出现所有的成员.

现在我们重新生成之后访问   /Store/Details/5 :

现在我们给Browse方法一个相应的修改:

更新StroeController.Browse方法:

2 public ActionResult Browse(string genre)
3         {
4             var genreModel = new Genre { Name = genre };
5             return View(genreModel);
6         }

给Browse 添加视图,强类型关联到Genre

更新Browse.cshtml代码:

2 @model MvcMusicStore.Models.Genre
3 @{
4     ViewBag.Title = "Browse";
5 }
6 <h2>Browsing Genre: @Model.Name</h2>

重新生成项目并访问  /Store/Browse?Genre=Disco:

  最后,我们给StoreController.Index一个稍微复杂的逻辑和视图来展示一个流派列表,我们使用一个Genres列表,而不是单个对象:

StoreController.Index代码:

 3         // GET: /Store/
 4         public ActionResult Index()
 5         {
 6             var genres = new List<Genre>
 7             {
 8                 new Genre { Name = "Disco"},
 9                 new Genre { Name = "Jazz"},
10                 new Genre { Name = "Rock"}
11             };
12             return View(genres);
13         }

给Index添加视图强类型管理到Genre,打开视图文件Models/Store/Index.cshtml,把第一行的接收参数生命更新:

2 @*注释*@
3 @*@model MvcMusicStore.Models.Genre  *@
4 @model IEnumerable<MvcMusicStore.Models.Genre>

@**@表示注释代码

第四行代码表示我们将接受多个Genre对象;

我们使用 IEnumerable<Genre>而不是  List<Genre>,是因为IEnumerable更为通用,我们可以传递任意实现IEnumerable接口的参数类型.

下面我们将遍历Genre对象:

 2 @*@model MvcMusicStore.Models.Genre  *@
 3 @model IEnumerable<MvcMusicStore.Models.Genre>
 4 @{
 5     ViewBag.Title = "Store";
 6 }
 7 <h3>Browse Genres</h3>
 8 <p>
 9     Select from @Model.Count()
10     genres:
11 </p>
12 <ul>
13     @foreach (var genre in Model)
14     {
15         <li>@genre.Name</li>
16     }
17 </ul>

  任然有非常强悍的智能感知:比如输入@Model会出来所有支持的成员;

循环内部,每个 var生命的genre 也可以智能感知所有的成员;

现在我们已经可以循环传入对象列表,并输出对象总数以及每个对象的信息,以后我们会生成编辑、查看详细信息和删除操作到每一项,现在我们先来看看简单列表:

重新生成项目,访问  /Store:

 

  4.添加站内链接

刚才的 /Store页面展示了一组Genre对象的Name属性作为普通文本,我们给他们加上链接,通过点击访问相关的详细信息/Store/Browse,当我们点击 "Disco",能够跳转到/Store/Browse?genre=Disco,我们更新/Views/Store/Index.cshtml的代码:

2 <ul>
3     @foreach (var genre in Model)
4     {
5         <li><href="/Store/Browse?genre=@genre.Name">@genre.Name</a></li>
6     }
7 </ul>

  这样可以实现,但是不是很好的方式,比如我们要更新Browse为BrowseDetail,那就需要检索整个项目来查找需要更新的地方.

另一个实现方式就是利用 HTML Helper 方法.Asp.net Mvc包含HTML Helper方法,在View编辑器中,我们可以使用它来完成相关的任务. Html.ActionLink()是一个特别有用的方法,使用它创建链接,维护路径,还是确保URL编码都比较简单,

  Html.ActionLink()有几个重载允许我们传入需要的各种参数, 在示例中我们仅需要提供链接文本和目标Action,比如我们可以在Store Details 页面点击"Go to Store Index" 连接到"/Store"页面,用法如下:

2 @Html.ActionLink("Goto the Store Index", "Index")

  链接到Browse页面需要一个参数,所以我们需要另外一个重载,它将支持三个参数:

 

    • 链接文本
    • 控制器名称
    • 参数 包括参数名和参数值

 

  下面看一下代码:

 2 @*@model MvcMusicStore.Models.Genre  *@
 3 @model IEnumerable<MvcMusicStore.Models.Genre>
 4 @{
 5     ViewBag.Title = "Store";
 6 }
 7 <h3>Browse Genres</h3>
 8 <p>
 9     Select from @Model.Count()
10     genres:
11 </p>
12 <ul>
13     @foreach (var genre in Model)
14     {
15         <li>@Html.ActionLink(genre.Name,
16 "Browse"new { genre = genre.Name })</li>
17     }
18 </ul>

  重新生成项目,访问  /Store/ :

  查看源代码:

2 <ul>
3         <li><href="/store/Browse?genre=Disco">Disco</a></li>
4         <li><href="/store/Browse?genre=Jazz">Jazz</a></li>
5         <li><href="/store/Browse?genre=Rock">Rock</a></li>
6 </ul>

  可以发现,解析出来的html代码和预期的相同.

个人感悟

通过这章,可以发现,在mvc中,业务逻辑和表示层分离的程度非常高,几乎可以同时开始编码,而不用担心其他问题.我们将在下一章介绍模型和数据访问.


posted @ 2012-09-16 13:30  JackZ  阅读(2611)  评论(4编辑  收藏  举报