原文链接:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/adding-a-view
在这一小节,我们将会修改类HelloWorldController来使用视图模板文件,把为客户端生成HTML响应的过程封装起来。
我们将使用在ASP.NET MVC 3中介绍的Razor视图引擎来创建视图模板文件。基于Razor的视图模板使用.cshtml做文件扩展名,它提供了一种优雅的方式来使用c#生成HTML内容。在创建一个视图模板时Razor可以使我们编写更少的代码,使我们的编码过程快速流畅。
目前Index方法只会返回硬编码在controller中的字符串。通过下面的代码可以使Index方法返回一个视图对象。
public ActionResult Index() { return View(); }
上面的Index方法是用一个视图模板来生成返回给浏览器的HTML响应。Controller方法(又称action方法),比如Index,通常返回一个ActionResult对象或者从ActionResult派生的对象,而不是像string这样的简单类型。
在这个项目里,我们为Index方法添加一个视图模板,在Index方法内部右键单击,选择"Add View"。
Add View对话窗口会出现,我们使用默认设置,直接单击Add按钮。
这样做会创建MvcMoview\View\HelloWorld文件夹并且会在该文件夹下创建Index.cshtml文件,你可以在解决方案资源管理器(Solution Explorer)中看到。
下面是新创建的Index.cshtml中的内容
在最后一行加入新代码,修改后的index.cshtml文件内容如下
@{ ViewBag.Title = "Index"; } <h2>Index</h2> <p>Hello from our View Template!</p>
让我们启动程序浏览HelloWorld controller(http://localhost:xxxx/HelloWorld),controller中的Index方法并不会做太多的工作,只是单纯执行return View()语句,来指明Index方法会使用一个视图模板来来渲染浏览器。因为我们并没有显示指出要使用的视图模板文件的名字,ASP.NET MVC 会默认使用\Views\HelloWorld文件夹下的Index.cshtml视图文件。下面的截图显示了被硬编码在视图中的字符串"Hello from our View Template"。
看起来好多了。但是,注意在浏览器标题栏里展示的"Index-My ASP.NET M..."和在页面上方大大的超链接"your logo here"。在"your logo here"之后是注册和登录的超链接,然后是Home,About和Contact页面的超链接,让我们来做点事情改变这个页面。
首先,来改变页面顶部的标题"your logo here."。这是每一个页面都会有的文本。尽管在应用程序中的每一个页面它都会出现,事实上在项目中只有一个地方实现了它。查看解决方案资源管理器的/Views/Shared文件夹并且打开_Layout.cshtml文件。这个文件被叫做布局页面(layout page)并且作为其它页面共享的“外壳”。
布局模板允许我们为网站在一个地方制定HTML容器布局然后将其应用到多个页面中。找到代码中的@RederBody()那一行。RenderBody是一个占位符,在所有特定的视图中会替换掉它。例如,如果你选择了About超链接,Views\Home\About.cshtml视图会被渲染到RenderBody方法所在的地方。
改变布局模板中网页头部的内容(body标签下的<header>),把"your logo here"改成"MVC Movie"
<div class="float-left"> <p class="site-title">@Html.ActionLink("Mvc Movie", "Index", "Home")</p> </div>
使用下面的标记替换掉title元素中的内容
<title>@ViewBag.Title - Movie App</title>
运行程序,我们会看到现在页面头部展示的是"MVC Movie"。点击About超链接,你同样会看到头部的"MVC Movie"。我们只需要在布局模板中做一次刚改,就可以影响到所有的页面。
现在,让我们来改变一下Index视图的标题。
打开MvcMovie\VIews\HelloWorld\Index.cshtml文件。有两个地方需要做修改:第一,出现在浏览提标题中的文字;第二,二级标题(<h2>元素).我们把这两处改的有点不一样,这样就能看出来哪一处代码会影响到程序的哪一部分。
@{ ViewBag.Title = "Movie List"; } <h2>My Movie List</h2> <p>Hello from our View Template!</p>
为了指定展现的HTML标题,上面的代码为ViewBag(存在于Index.cshtml视图模板中)对象的Title属性赋了值。如果你回过头来看一下布局模板中的代码,你会发现我们之前修改的布局模板html中的<head>节点下的<title>元素内部使用了ViewBag的这个属性值。通过使用ViewBag,我们可以轻松地在布局文件和视图模板之间传递参数。
启动应用程序浏览http://localhost:xxxx/HelloWorld。注意一下浏览器的标题,主标题和次标题已经改变了(如果你没有看到改变的话,可能是因为你看到了浏览器缓存的内容,按下ctrl+F5强制浏览器向服务器请求新页面)浏览器标题由我们在Index.cshtml视图模板中设置的Viewbag.Title和在布局文件中添加的" – Movie App"共同构造出来。
同样要注意到Index.cshtml和_Layout.cshtml视图模板中的内容是怎样合并到一起生成一个单一的HTML响应发送到浏览器的。布局模板使我们修改应用中的多个页面变得非常容易。
我们仅仅使用的一点点”数据“,是硬编码的"Hello from out View Template",现在我们的MVC程序有了V和C,但是还没有M,马上我们就会介绍如何创建一个数据库并且从中检索model数据。
在我们使用数据库和讨论model之前,先谈谈关于从controller向view传递数据的话题。Controller类在响应传入的URL请求时被调用。一个controller其实是一个类,这个类由开发者编写,用来处理传入的浏览器请求,这个类从数据库中检索数据并最终决定将什么样的响应发回浏览器。在controller生成HTML响应的时候可以使用视图模板(View Template)。
Controller负责为视图模板提供请求的任何数据或者对象。最好的实践是:视图模板完全不关心业务逻辑或者并且从不和数据库直接交互。视图模板应该仅仅使用到controller传递给它的数据。坚持“关注点分离(separation of concerns)”原则有助于我们写出整洁,可测试和易维护的代码。
目前,HelloWorldController中的Welcom方法接收name和numTimes参数并且直接将其输出到浏览器。我们现在使用视图模板替代简单的字符串。视图模板将负责动态生成响应,这就意味着我们需要从controller传递恰当的数据给它。我们可以通过在controller中把数据存放到视图模板也可以访问的ViewBag对象中来做到这一点。
让我们回到HelloWorldController.cs文件,并且更改Welcom方法,来给ViewBag对象添加Message和NumTimes数据。ViewBag是一个动态类型(c#里的dynamic),也就是说我们可以给它添加任何属性,在我们给ViewBag添加属性之前它是没有任何属性的。ASP.NET MVC model binding system会自动将url中查询字符串里的参数映射到方法参数。完整的HelloWorldController.cs文件内容如下:
using System.Web; using System.Web.Mvc; namespace MvcMovie.Controllers { public class HelloWorldController : Controller { // // GET: /HelloWorld/ public ActionResult Index() { return View(); } // // GET: /HelloWorld/Welcome/ public ActionResult Welcome(string name, int numTimes = 1) { ViewBag.Message = "Hello " + name; ViewBag.NumTimes = numTimes; return View(); } } }
现在包含了数据的ViewBag会自动传递给View。
接下来,我们需要一个Welcom视图模板,我们需要先编译一下项目。选择“Build”菜单里的"Build MvcMovie"选项。
在Welcom方法内部右键单击选择"Add View"。
会弹出如下的Add View对话框
单击Add,在Welcom.cshtml文件里的<h2>元素下面添加代码。创建一个循环来按照用户的要求输出"Hello",完整的Welcom.cshtml文件内容如下
@{ ViewBag.Title = "Welcome"; } <h2>Welcome</h2> <ul> @for(int i=0;i<ViewBag.NumTimes;i++) { <li>@ViewBag.Message</li> } </ul>
运行应用程序访问如下的URL:
http://localhost:xx/HelloWorld/Welcome?name=Scott&numtimes=4
URL里携带的数据通过model binder会传递给controller。controller将数据打包到ViewBag对象然后传递给View。View将数据展示为html。
在上面的例子中,我们使用ViewBag对象来从controller传递数据给view。在接下来的文章里,我们会使用view model来传递数据。使用view model来传递数据比ViewBag对象更好,更多的内容可以参考Dynamic V Strongly Typed Views。