ASP.NET MVC Music Store教程(3):视图和视图模型

转自http://firechun.blog.163.com/blog/static/31804522201102711480936/

到目前为止,我们仅仅从控制器动作返回字符串,这是一个了解控制器如何工作的好方法,但这并不是你想要的真实的Web应用程序。我们想要一个更好的方法为访问我们站点的浏览器产生HTML,使用模板文件可以更容易地定制发回的HTML内容。

添加视图模板

要使用视图模板,可以修改HomeController的Index方法,让它返回ActionResult,就象下面这样返回View():

public class HomeController : Controller 

    // 
    // GET: /Home/ 
    public ActionResult Index() 
    { 
        return View(); 
    } 
}

上述修改标志着返回的字符串被替代,我们使用“View”产生返回结果。

现在为我们的项目添加一个适当的视图,把光标定位到Index动作方法上,单击右键,选择“添加视图”,进入

ASP.NET MVC Music Store教程(3):视图和视图模型
 
ASP.NET MVC Music Store教程(3):视图和视图模型
 
 

 “添 加视图”对话框允许我们方便快捷地产生视图模板文件。默认情况下,“添加视图”对话框会预先填写视图模板的名称以匹配使用它的动作方法,因为我们在 HomeController的Index动作方法上使用右键菜单上的“添加视图”,因此“添加视图”对话框默认填写Index作为视图名称,我们不需要 改变任何选项,点击“添加”按纽。

点击“添加”按纽后,VS在Views\Home目录中创建了一个新的模板:Index.cshtml,如果目录不存在,VS会自动创建它。

ASP.NET MVC Music Store教程(3):视图和视图模型
 

 “Index.cshtm”的文件名和文件夹非常重要,遵循了ASP.NET MVC约定。\Views\Home匹配HomeController控制器,视图模板名称——Index则匹配显示该视图的控制器动作方法。

使用ASP.NET MVC命名约定返回视图,可以让我们避免显示指定视图模板的名称和位置。当我们在HomeController中编写如下代码时,默认情况下将呈现\Views\Home\Index.cshtml视图模板。

public class HomeController : Controller 

    // 
    // GET: /Home/ 
    public ActionResult Index() 
    { 
        return View(); 
    } 
}

在“添加视图”对话框中按下“添加”按纽后,VS创建并打开Index.cshtml视图模板,Index.cshtml的内容如下所示:

@{ 
    ViewBag.Title = "Index"; 

<h2>Index</h2>

视 图使用了Razor,一种比ASP.NET及较早版本的ASP.NET MVC使用的Web Forms引擎更简洁的语法。ASP.NET MVC 3仍然支持Web Forms视图引擎,但大多数开发人员认为Razor视图引擎比它更适合ASP.NET MVC 的开发。

首三行用ViewBag.Title设置页面标题,我们很快会看到它是如何工作的更多细节,但现在先让我们更改视图页面的文本,把<h2>标签中的内容改成如下所示:

<h2>This is the Home Page</h2>

运行程序,在主页中我们可以看到新的文本:

ASP.NET MVC Music Store教程(3):视图和视图模型
大多数网站在多个页面之间有相同的内容:导航栏、脚注、Logo图片、样式引用等等,Razor视图引擎自动在/Views/Shared 文件夹下创建的_Layout.cshtml使我们更容易管理。
ASP.NET MVC Music Store教程(3):视图和视图模型
 双击这个文件,内容如下:
<!DOCTYPE html> 
<html> 
<head> 
    <title>@ViewBag.Title</title> 
    <link href="@Url.Content("/Content/Site.css")" 
rel="stylesheet" type="text/css" /> 
    <script src="@Url.Content("/Scripts/jquery-1.4.4.min.js")" 
type="text/javascript"></script> 
</head> 
<body> 
    @RenderBody() 
</body> 
</html>
每个视图自己的内容由@RenderBody()命令显示,除此之外的任何共用的内容都可以添加到_Layout.cshtml中。我们希望网站的所有页面都有一个链接到Home和Store的头部,直接在@RenderBody()前面添加这些代码即可。
<!DOCTYPE html> 
<html> 
<head> 
    <title>@ViewBag.Title</title> 
    <link href="@Url.Content("/Content/Site.css")" 
rel="stylesheet" type="text/css" /> 
    <script src="@Url.Content("/Scripts/jquery-1.4.4.min.js")" 
type="text/javascript"></script> 
</head> 
<body> 
    <div id="header"> 
        <h1> 
            ASP.NET MVC MUSIC STORE</h1> 
        <ul id="navlist"> 
            <li class="first"><a href="/" id="current">Home</a></li> 
            <li><a href="/Store/">Store</a></li> 
        </ul> 
    </div> 
    @RenderBody() 
</body> 
</html>
(引用样式的说明略,从http://mvcmusicstore.codeplex.com下载源代码,所有图片和样式脚本、数据库都在MvcMusicStore-Assets目录中)
 运行应用程序,新的主页是下面的样子:
ASP.NET MVC Music Store教程(3):视图和视图模型
 让我们看看做了哪些修改:
  • 因为视图模板遵循标准命名约定,HomeController的Index动作方法通过调用“return View()”找到并且显示\Views\Home\Index.aspx视图模板。
  • 通过在\Views\Home\Index.aspx中的定义,主页显示了一条简单的欢迎信息。
  • 使用母版页,欢迎信息呈现出标准的HTML布局。

使用模型(Model)把信息传递给视图

视图模板仅仅显示硬编码的HTML内容不足以构建一个令人感兴趣的网站,要创建动态网站,我们应该从控制器动作中传递信息到视图模板。

在Model-View-Controller(模型-视图-控制器)模式中,模型是对应用程序要呈现的数据的对象引用,通常来说,模型对象相当于数据库中的表,但这里不是。

返回ActionResult的控制器动作方法可以把模型对象传递给视图,这使得控制器干净地封装了所有需要的信息生成一个响应,把这些信息传递给视图模板并生成适当的HTML响应。在控制器动作中看它是最容易理解的,那么让我们开始吧。

首先,我们创建一些模型类来描述音乐仓库的类别和唱片,让我们从创建Genre类开始。在你的项目中,右键单击“Models”文件夹,选择“添加->类”,并将文件命名为Genre.cs

ASP.NET MVC Music Store教程(3):视图和视图模型ASP.NET MVC Music Store教程(3):视图和视图模型

 在创建的类中增加一个公用的字符串属性——Name

public class Genre 

    public string Name { get; set; } 
}

注意:这里你可能会感到奇怪, { get; set; } 是C#自动属性(C#3.0支持)这让我们方便定义属性而不需要声明字段。

下面,按相同的步骤添加唱片类(Album.cs),它有两个属性:Title和Genre

 public class Album 

    public string Title { get; set; } 
    public Genre Genre { get; set; } 
}

现在,我们可以修改StoreController,使用视图显示模型信息:

ASP.NET MVC Music Store教程(3):视图和视图模型

 我 们修改StoreController中的Details动作,让它显示单个唱片的信息。在StoreController类的顶部增加using语句以 包含MvcMusicStore.Models命名空间,这样,我们每次使用Album类时,不需要输入 MvcMusicStore.Models.Album ,using部分看起来如下所示:

using System; 
 using System.Collections.Generic; 
 using System.Linq; 
 using System.Web; 
 using System.Web.Mvc; 
 using MvcMusicStore.Models; 
 下面,我们修改Details控制器动作,让它返回ActionResult而不是字符串,我们曾经对HomeController的Index方法做过同样的修改。

public ActionResult Details(int id)

现在我们修改业务逻辑为视图返回一个Album对象,在本教程的最后,我们会从数据库接收数据,但现在,让我们先从“模拟数据”开始吧。

public ActionResult Details(int id) 
 { 
    var album = new Album { Title = "Album " + id }; 
    return View(album); 
 }

(对var类型变量的解释,不写了)

现在可以创建使用Album生成HTML响应的视图模板,在此之前我们需要生成项目以便让“添加视图”对话框知道我们新建的Album类,在“生成”菜单中选择“生成MvcMusicStore”。

ASP.NET MVC Music Store教程(3):视图和视图模型

 设 置好支持的类后,我们准备创建视图模板,在Details方法上单击右键并在快捷菜单上选择“添加视图”,就象之前为HomeController创建视 图模板一样,由于我们从StoreController中创建,默认会产生 文件\Views\Store\Details.aspx。

和之前不同的是,这次我们把“创建强类型视图”勾选上,然后在“视图数据类”下拉框中选择Album类,“添加视图”对话框将产生视图模板,并将Album对象传递给它。

ASP.NET MVC Music Store教程(3):视图和视图模型

 (以下和原文不同,微软更新太快,原文已经使用MVC 3,因为时间关系,目前我还不打算在我们的项目中使用MVC 3 的Razor语法,因此下面全部使用MVC 2完成,功能和原文保持一致)

Details.aspx的页面指令中包含以下代码:

Inherits="System.Web.Mvc.ViewPage<MvcMusicStore.Models.Album>"

表示这是个Album的强类型视图,可以让我们更容易访问模型的属性,并受VS的“智能感应器”的支持。

在<h2>标签中显示Album的Title属性:

    <h2>Album:<%:Model.Title %></h2>
注意当我们输入<%:之后,VS的智能感应器会显示,Model是默认的Album对象名称,并且可以在智能感应器中看到相关的属性和方法。

(注:<%: %>是ASP.NET 4的新语法,等效于<%=Server.HtmlEncode()%>)

运行应用程序并访问URL /Store/Details/5,我们看到了唱片的详细信息:

ASP.NET MVC Music Store教程(3):视图和视图模型

 现在我们同样更新StoreController的Browse动作方法,修改方法的返回值为ActionResult,修改方法的业务逻辑返回一个Gener对象给视图。

public ActionResult Browse(string genre) 
 { 
    var genreModel = new Genre { Name = genre }; 
    return View(genreModel); 
 }

在Browse方法上单击右键选择“添加视图”,添加一个Genre的强类型视图。

ASP.NET MVC Music Store教程(3):视图和视图模型

 更新视图代码:

<h2>Browsing Genre:<%:Model.Name %></h2>

运行应用程序并访问URL /Store/Browse?Genre=Disco,我们看到如下的浏览页面:

ASP.NET MVC Music Store教程(3):视图和视图模型

 最后,让我们做一个稍微复杂点的修改:让StoreController的Index动作方法和视图显示仓库中所有类别的列表,我们使用Genre的集合而不是单个Genre对象。

public ActionResult Index() 

    var genres = new List<Genre> 
    { 
        new Genre { Name = "Disco"}, 
        new Genre { Name = "Jazz"}, 
        new Genre { Name = "Rock"} 
    }; 
    return View(genres); 
 }

在Index方法上单击右键选择“添加视图”,类型选择Genre,视图内容选择“List”:

ASP.NET MVC Music Store教程(3):视图和视图模型
 注意Index.aspx的Page指令部分和之前不同,如果在刚才的“添加视图”里没有把“视图内容”选择为“List”,也可修改成如下所示:
Inherits="System.Web.Mvc.ViewPage<IEnumerable<MvcMusicStore.Models.Genre>>"
把代码改成如下所示:
    <h3>
        Browse Genres</h3>
    <p>
        Select from <%:Model.Count()%> genres:</p>
    <ul>
        <%foreach (var genre in Model){%>
        <li>
            <%:genre.Name%></li>
        <%} %>
    </ul>
(本人注:对照一下原文使用的MVC 3的Razor语法,可以体会出Razor语法的优势)
注意原来生成的代码为列表的每一项都生成了Edit,Details和Delete链接,不过我们在稍后的仓库管理中再应用这些功能,因此我们用上面较简单的代码替换了自动生成的代码。
运行程序,浏览/Store,我们可以看到类别的数量和列表都显示出来。
ASP.NET MVC Music Store教程(3):视图和视图模型
 添加页面之间的链接
/Store URL把当前类别的名称作为纯文本列出,现在让我们用一个指向/Store/Browse URL的链接来替换这些纯文本,当我们在类别名称——比如“Disco”上点击时可以被导航到/Store/Browse?genre=Disco URL,更新\Views\Store\Index.aspx视图模板,修改成如下代码:
        <%foreach (var genre in Model){%>
        <li>
            <a href="/Store/Browse?genre=<%:genre.Name%>"><%:genre.Name%></a></li>
        <%} %>
运行没问题,不过使用硬编码可能会为我们带来麻烦,例如,如果我们想重命名控制器,我们必须搜索代码中所有链接到该控制器的地方并进行修改。
一 个可供选择的方式是,我们可以利用HTML helper中的方法。ASP.NET MVC中包含的HTML helper方法允许我们从视图模板中执行象这种要求的各种通用任务。Html.ActionLink() helper方法就是特别有用的方法之一,它可以轻松地帮助我们构建HTML <a>标签,并且处理那些令人厌烦的细节——比如确定URL路径是否经过恰当的URL编码(Encode)。
Html.ActionLink() 有好几个重载,允许我们为链接指定所需的信息,在我们这个简单的例子中,我们只需提供链接文本和超链接被点击时指向的动作方法。例如,我们使用下列代码在 /Store/Details.aspx中创建一个指向StoreController中的Index方法的链接:
<%:Html.ActionLink("Go to the Store Index", "Index")%>

注意:在上面的例子中,因为是从当前视图链接到同一个控制器的另一个动作,所以不需要指定控制器的名称。

链接到Browse页面需要传递一个参数,这里我们用Html.ActionLink()有三个参数的重载:

  • 1.链接的文本——使用类型名称(genre.Name)
  • 2.控制器动作名称——Browse
  • 3.路由参数——需要指定参数名称和值,参数名称是genre,值是genre.Name

新的代码:

        <%foreach (var genre in Model){%>
        <li>
            <%:Html.ActionLink(genre.Name,"Browse",new {genre=genre.Name}) %>
        </li>
        <%} %>

现在运行我们的项目并访问 /Store/ URL,我们可以看到类别列表,每个类别都是一个超链接,点击后会把我们带到/Store/Browse?genre=[genre] URL。

网页产生的HTML代码看起来如下所示:

<ul> 
    <li><a href="/Store/Browse?genre=Rock">Rock</a> 
</li> 
    <li><a href="/Store/Browse?genre=Jazz">Jazz</a> 
</li> 
    <li><a href="/Store/Browse?genre=Country">Country</a> 
</li> 
    <li><a href="/Store/Browse?genre=Pop">Pop</a> </li> 
    <li><a href="/Store/Browse?genre=Disco">Disco</a> 
</li> 
</ul>

(本人注:关于Html.ActionLink()的用途和好处,可以参看我的另一篇文章:布署ASP.Net MVC应用程序时的链接地址问题

 
上一篇:开始云为学校打造完整文件管理体系


下一篇:《Arduino开发实战指南:LabVIEW卷》——第1章 Arduino硬件