Forms and Html Helpers — By Scott Allen
本章内容
- 了解表单
- 如何运用HTML helpers
- editing and inputting helpers
- displaying and rendering helpers
Html helpers,顾名思义,它帮助你生成HTML。在编辑器上编写HTML元素看似简单,你或许会疑惑有没有必要使用它。的确,标签名称都是很简单的,所以重点在于链接的地址是否正确以及表单元素是否提供了合适的键值给模型绑定、绑定失败时显示适当的错误信息。要处理以上所有的问题,仅仅靠HTML标记就略显不足了。它还需要一些协调用于视图和运行时之间。在本章中,你会看到如何简单地实现这种协调。在你开始使用helper前,你要先了解下forms,因为forms常常是最需要使用Html Helper的。
使用表单
你或许会感到疑惑,这本面向专业Web开发人员的书籍为什么要花时间来讲解Html的form标签,难道它不是非常容易的吗?
这主要有两个理由:
- form标签是非常强大的!若没有form标签,互联网将变成只能用于查看的文档知识库。你将无法在Web中搜索,不能网上购物。如果一个邪恶的天才在今晚将所有网站上的form标签偷走了,那么明天午餐时间将乱成一片。
- 许多学习MVC框架的开发者都接触过ASP.NET WebForms。WebForms并没有真正体现form标签的实际作用(你可理解为WebForms利用form标签以达到它自身的目的)。这让很多WebForms开发者忘了form标签的本职—比如创建一个HTTP GET的请求。
行为和方法
表单通常包含一系列的输入元素:buttons,checkboxes,text inputs,等等。它们使用户能够在页面中输入信息并提交给服务端。但是服务器端是谁?如何将信息传给服务器端?这些问题的答案就是form标签的两个最重要的属性:action和method。
action属性告诉浏览器将信息发送到哪里,所以action自然包含一个URL。这个URL可以是相对路径也可以是绝对路径。下面的表单会发送一个搜索请求给Bing的搜索页面:
<form action=”http://www.bing.com/search”> <input name=”q” type=”text” /> <input type=”submit” value”Search!” /> </form>
上面的代码中,form标签并没有包含一个method属性。该属性告诉浏览器在发送信息的时候是使用HTTP POST还是HTTP GET方法。你或许会认为默认的提交方法是POST,毕竟你通常都是提交表单的方式来更新个人息,留言等。然而,默认的方法实际是"GET",所以默认情况下表单是以GET方式发送请求:
<form action=”http://www.bing.com/search” method=”get”> <input name=”q” type=”text” /> <input type=”submit” value”Search!” /> </form>
当用户以GET方式提交表单,浏览器会在表单里面获取输入元素的键值并将它们组合到查询字符串里面。换句话说,上面的表单会浏览器发送这样的URL(假设用户正在搜索love这个词):http://www.bing.com/search?q=love
用GET还是POST
当你把method属性设置为POST,那么浏览器则会将键值放到HTTP请求中的正文中去。虽然你能够向搜索引擎成功发送POST请求并查看搜索结果,但其实GET请求更值得推荐。因为GET请求将参数存放在URL上面,这样你就能够将包含这些参数的URL写到email或网页中。
更重要的是,GET其实才是这项工作的正确选择,因为GET本来就表示一个只读操作。你可以毫无顾虑地频繁发送GET请求给服务端,因为GET请求并不会(不应该会)改变服务器端的状态。
另一方面,POST则是一种用于提交身份认证或交易的请求,比如添加一个专辑到购物车,或更改密码。POST请求通常会更改服务器端的状态,频繁地POST请求有时会导致不良状态(比如重复付款)许多浏览器会帮助用户防止重复提交POST请求(下图展示了Chrome浏览器如何预防用户刷新一个POST请求)

网站通常在读取的时候用GET,写入的时候用POST。比如:结帐音乐专辑用POST,搜索音乐、查看下一篇文章这些则用GET。
用一个搜索表单来搜索音乐
假设你想要让用户能够在你的音乐商店主页上搜索音乐。你就需要一个有action及method属性的表单。对应的视图代码如下:
<form action=”/Home/Search” method=”get”> <input type=”text” name=”q” /> <input type=”submit” value=”Search” /> </form>
下一步是在HomeController中实现Search方法。下列的代码简单地假设用户是以专辑名称来搜索音乐的:
public ActionResult Search(string q) { var albums = storeDB.Albums .Include(“Artist”) .Where(a => a.Title.Contains(q) || q == null) .Take(10); return View(albums); }
Search行为接收一个名为q的string参数,MVC框架会在查询字符串中自动找到该值。
接下来控制器会告诉MVC框架要呈现一个视图,你可以在视图目录的Home文件夹下创建一个简单的Search.cshtml文件来展示搜索结果:
@model IEnumerable<MvcMusicStore.Models.Album> @{ ViewBag.Title = “Search”; } <h2>Results</h2> <table> <tr> <th>Artist</th> <th>Title</th> <th>Price</th> </tr> @foreach (var item in Model) { <tr> <td>@item.Artist.Name</td> <td>@item.Title</td> <td>@String.Format(“{0:c}”, item.Price)</td> </tr> } </table>

当然,很多时候并不会像这个搜索表单一样这么简单。实际上,这样的表单缺少灵活性。如果你改变了网站的目录或者路由规则的定义,这样的硬编码则会使用户找不到该资源:注意我们将表单的action属性值硬编码为"Home/Search"。
一个更好的方法是将action的值设置为动态(可计算)的,幸运地,HTML helper已经为我们提供了这样的方法。
@using (Html.BeginForm(“Search”, “Home”, FormMethod.Get)) { <input type=”text” name=”q” /> <input type=”submit” value=”Search” /> }
BeginForm helper告诉路由引擎如何到达HomeController的Search action。该方法的幕后其实是利用了RouteTable.Routes里面的一个GetVirtualPath的方法来实现的,如果你想要不借助HTML helper来完成这项任务,你需要编写如下代码。
@{ var context = this.ViewContext.RequestContext; var values = new RouteValueDictionary{ { “controller”, “home”}, { “action”, “index”} }; var path = RouteTable.Routes.GetVirtualPath(context, values); } <form action=”@path.VirtualPath” method=”get”> <input type=”text” name=”q” /> <input type=”submit” value=”Search2” /> </form>
前面的例子演示了HTML helpers的本质。它们不但没有脱离你的控制,还能帮助你编写更少的代码来完成任务。
HTML HELPERS
HTML helpers是一系列供您在视图的HTML中通过HTML属性调用的方法。你也可以调用URL helpers(通过URL属性),AJAX helpers(通过Ajax属性)。所有这些(helpers)助手都有一个共同的目的:使视图更简洁易懂。
大多数helpers,尤其是HTMl helpers,作用于输出HTML标记。举个例子,之前你看过的BeginForm helper就是用于为你的搜索表单生成一个健壮的form标签:
@using (Html.BeginForm(“Search”, “Home”, FormMethod.Get)) { <input type=”text” name=”q” /> <input type=”submit” value=”Search” /> }
BeginForm helper输出的标记和你之前硬编码的是一样的。然而,在幕后其实是helper与路由引擎协调工作并生成一条正确的URL,所以这样的代码更能适应不同的应用程序部署。
你还可以使用下列这种稍具对称性的方式来实现同样的功能:
@{Html.BeginForm(“Search”, “Home”, FormMethod.Get);} <input type=”text” name=”q” /> <input type=”submit” value=”Search” /> @{Html.EndForm();}
正如你的好朋友一样,HTML helper能够帮你远离麻烦。本章接下来你会了解到的许多HTML helpers都作用于输出模型值。它们在输出值前都会进行HTML编码。举个例子,接下来你会看到的TextArea helper(用于输出textarea元素)
@Html.TextArea(“text”, “hello <br/> world”)
该方法的第二个参数是要呈现的值。上面的例子在这个参数中嵌入了HTML代码,不过TextArea helper会输出如下标记:
<textarea cols=”20” id=”text” name=”text” rows=”2”> hello <br /> world </textarea>
给Helpers添加其他属性
在提供安全性的同时,helpers还提供了灵活的可控制性。下例是BeginForm helper的一个重载方法:
@using (Html.BeginForm(“Search”, “Home”, FormMethod.Get, new { target = “_blank” })) { <input type=”text” name=”q” /> <input type=”submit” value=”Search” /> }
如上代码,你为BeginForm的htmlAttributes参数提供了一个未知类型的对象。MVC框架里面几乎所有的HTML helper都有这样的一个重载方法。你还可以找到类型为IDictionary<string,object>的另一个重载。上述代码将呈现如下form标签:
<form action=”/Home/Search” method=”get” target=”_blank”>
有必要的话,你还可以通过htmlAttributes参数来设置更多的属性。在这之前有几个特殊的属性问题需要注意:
例如:设置class属性的时候,由于class是一个C#的保留关键字,所以你必须在它前面加上"@":
@using (Html.BeginForm(“Search”, “Home”, FormMethod.Get,
new { target = “_blank”, @class=”editForm” }))
另一个问题是:给属性设置带连接符的名称时(如data-val)。连接符在C#属性名中是无效的,但幸运的是,所有HTML helpers在呈现HTML时都会将属性名中的下划线转换成连接符。如下代码:
@using (Html.BeginForm(“Search”, “Home”, FormMethod.Get,
new { target = “_blank”, @class=”editForm”, data_validatable=true }))
会生成这样的HTML标记:
<form action=”/Home/Search” class=”editForm” data-validatable=”true” method=”get” target=”_blank”>
在下一节,你会了解到helpers是如何工作的以及其他一些helpers。
HTML helpers的内部
每一个Razor视图都继承了基类的一个Html属性。该Html属性的类型是System.Web.Mvc.HtmlHelper<T>,T是一个代表视图模型的泛型参数(默认为动态类型)。这个类提供了一些供你在视图调用的实例方法,如EnableClientValidation。然而,在这个类里面你不会找到之前用到的BeginForm方法的定义。取而代之,框架将这些hepers定义为扩展方法。
扩展方法适用于HTML helpers主要有两个理由。首先,扩展方法只有在同个命名空间范围内才可用。所有的用于HtmlHelper的MVC扩展方法都存在于SYstem.Web.Mvc.Html命名空间。如果你不喜欢内置的扩展方法,你可以删除这个命名空间并构建你自已的扩展方法(在14章你会学到如何创建自定义的helper)。
创建专辑编辑表单
如果你需要创建一个供用户编辑专辑信息的视图,你会编写如下视图代码:
@using (Html.BeginForm()) { @Html.ValidationSummary(excludePropertyErrors: true) <fieldset> <legend>Edit Album</legend> <p> <input type=”submit” value=”Save” /> </p> </fieldset> }
代码中的有到的两个helpers在下文会再做说明。
Html.BeginForm
在上面你已经使用过BeginForm helper了。它将以POST请求当前URL,所以如果该视图的响应地址是/StoreManager/Edit/52,那么生成的form标签如下:
<form action=”/StoreManager/Edit/52” method=”post”>
由于你是在修改服务器端的专辑信息,所以是以POST提交请求。
Html.ValidationSummary
ValidationSummary helper用于将模型状态里面的验证提示信息字典以
一个无序的列表显示出来。它接收一个布尔类型的参数,该参数通知方法是否要排除掉属性级别的错误。换句话说,它会告诉summary是否只显示与模型本身相关联的错误信息,而排除掉那些与特定模型属性相关联的错误信息。这样会将属性级别的错误信息与Summary分开显示。
假设你在控制器的一个action上编写如下代码
ModelState.AddModelError(“”, “This is all wrong!”); ModelState.AddModelError(“Title”, “What a terrible name!”);
第一个错误的级别是模型级,因为你没有为错误提供一个特定属性的名称。第二个错误则关联了Title属性,所以在视图中它不会显示在validation summary区域内(除非你将布尔值改为false。)上面的视图将会呈现如下HTML:
<div class=”validation-summary-errors”> <ul> <li>This is all wrong!</li> </ul> </div>
ValidationSummary还提供了另外一个重载方法允许你提供一个头部信息。
添加输入
下面的代码提供了一个用于编辑专辑标题和类型的视图:
@using (Html.BeginForm()) { @Html.ValidationSummary(excludePropertyErrors: true) <fieldset> <legend>Edit Album</legend> <p> @Html.Label(“GenreId”) @Html.DropDownList(“GenreId”, ViewBag.Genres as SelectList) </p> <p> @Html.Label(“Title”) @Html.TextBox(“Title”, Model.Title) @Html.ValidationMessage(“Title”) </p> <input type=”submit” value=”Save” /> </fieldset> }
这个视图中包含了四个新的helpers:Label,DropDownList,TextBox,还有Validationmessage。我们先来讲TextBox。
Html.TextBox(and Html.TextArea)
TextBox helper呈现的是一个带有type="text"的input标签。
@Html.TextBox(“Title”, Model.Title)
输出Html:
<input id=”Title” name=”Title” type=”text” value=”For Those About To Rock We Salute You” />
TextBox还有一个近亲:TextArea。TextArea呈现用于输入多行文本的<textarea>元素。示例代码:
@Html.TextArea(“text”, “hello <br/> world”)
<textarea cols=”20” id=”text” name=”text” rows=”2”>hello <br /> world </textarea>
这里再提一次所有helpers在输出时都会先对模型值和属性值进行html编码。TextArea helper还有一个重载方法允许你定义列和行来控制text area的大小。
@Html.TextArea(“text”, “hello <br /> world”, 10, 80, null)
输出Html:
<textarea cols=”80” id=”text” name=”text” rows=”10”>hello <br /> world </textarea>
Html.Label
Label helper返回一个带for属性的<label/>元素。它接收一个字符串的参数用于确定呈现的文本和属性值。它的另一个重载方法允许你分开设置for属性和文本值。
Html.Label(“GenreId”)
输出Html:
<label for=”GenreId”>Genre</label>
如果你之前没有使用过label元素,那么你可能会对它的作用感到疑惑。label的作用是为其他输入元素提供附加信息,比如文本输入,并提升应用的辅助性。label的for属性包含相关联的输入元素ID。屏幕阅读设备能够根据label的文本值给用户提供关更好的输入提示信息。另外,如果用户单击label,浏览器会将焦点定位到关联的输入元素上。这对于多选框及单选框是非常有用的,能更好地改善用户体验。
细心的读者也许注意到了,label的文本值并不是显示GenreId,而是Genre。这是为什么呢?我们先看完其他helpers之后再回到这个话题。
Html.DropDownList(and Html.ListBox)
DropDownList和ListBox helpers都输出<select/>元素。DropDownList只允许选中单个,而ListBox可以同时选择多个(通过设置multiple属性)
通常情况下,select元素有两种作用:
1.显示一个可选的列表值
2.显示字段的当前值
在前面的例子中,Album类里面有一个GenreId的属性。你用select元素来呈现GenreId属性的值,及其他专辑分类。
在使用这些helpers前在控制器那边需要做一些准备工作 ,因为它们需要一些特殊的信息。列表需要一个SelectListItem的集合实例来代表可选项集。SelectListItem对象有三个属性:Text,Value,还有Selected属性。你可依靠框架自带的SelectList或MultiSelectList helper类来实现。这些类能够接收一个枚举类型并转换成SelectListItem对象集。以StoreManager的Edit action为例:
public ActionResult Edit(int id) { var album = storeDB.Albums.Single(a => a.AlbumId == id); ViewBag.Genres = new SelectList(storeDB.Genres.OrderBy(g => g.Name), ”GenreId”, ”Name”, album.GenreId); return View(album); }
控制器不仅提供了主要的模型信息,还为下拉列表helper提供了数据。第一个参数是原数据集合,第二个是属性值的字段,第三个是属性名的字段,最后一个是当前项的值。
如果你想避免反射所带来的开销并自已生成SelectListItem集,你可以使用LINQ的查询方法将Genres转换成SelectListItem对象集:
public ActionResult Edit(int id) { var album = storeDB.Albums.Single(a => a.AlbumId == id); ViewBag.Genres = storeDB.Genres .OrderBy(g => g.Name) .AsEnumerable() .Select(g => new SelectListItem { Text = g.Name, Value = g.GenreId.ToString(), Selected = album.GenreId == g.GenreId }); return View(album); }
Html.ValidationMessage
当模型状态字典里面出现特定字段的错误时,你可以使用ValidationMessage helper来显示信息。例如下面的控制器action里面,你故意给模型状态添加了一个Title属性的错误信息:
[HttpPost] public ActionResult Edit(int id, FormCollection collection) { var album = storeDB.Albums.Find(id); ModelState.AddModelError(“Title”, “What a terrible name!”); return View(album); }
在视图里,你可以用下列代码来显示错误信息:
@Html.ValidationMessage(“Title”)
输出html:
<span class=”field-validation-error” data-valmsg-for=”Title” data-valmsg-replace=”true”> What a terrible name! </span>
该错误信息只有当模型状态里面有一个键为Title的错误时才会出现。你也可以使用它的另一个重载来覆盖掉原先的错误信息:
@Html.ValidationMessage(“Title”, “Something is wrong with your title”)
输出html:
<span class=”field-validation-error” data-valmsg-for=”Title” data-valmsg-replace=”false”>Something is wrong with your title
Helpers,Models,and View Data
辅助方法使你能够灵活地控制HTML并避免花时间在如何界面上显示正确的控件。Html.TextBox、Html.DropDownList以及其他表单helpers会检查ViewData对象来获得当前值用于显示(ViewBag对象的所有值在ViewData同样可用)。
让我们来看一个简单的例子。如果你想要在一个表单中设置专辑价格,你会看到如下控制器代码:
public ActionResult Edit(int id) { ViewBag.Price = 10.0; return View(); }
你可以在视图通过给TextBox helper一个和ViewBag相同的名值来呈现一个textbox用于展示价格:
@Html.TextBox(“Price”)
输出html如下:
<input id=”Price” name=”Price” type=”text” value=”10” />
当helpers查找ViewData内部时,他们也会查看ViewData的内部属性对象。更改之前的action如下:
public ActionResult Edit(int id) { ViewBag.Album = new Album {Price = 11}; return View(); }
你可以使用下面的代码来展示专辑价格:
@Html.TextBox(“Album.Price”)
现在它输出的HTML是这样的:
<input id=”Album_Price” name=”Album.Price” type=”text” value=”11” />
如果在ViewData里面没有找到Album.Price,helper会尝试查找点号前的名称值,(Album),于是便找到了Album对象。接下来helper会将剩余部份(Price)的名称再与Album对象进行比较,然后找到可用的值。
注意输出HTML时,id属性的点号变成了下划线。 这是因为点号不是id属性的一个合法值,所以运行时会用HtmlHelper.IdAttributeDotReplacement这个静态属性的值来替换掉点号。
TextBox helper还可用于强类型的视图数据:
public ActionResult Edit(int id) { var album = new Album {Price = 12.0m}; return View(album); }
@Html.TextBox(“Price”);
<input id=”Price” name=”Price” type=”text” value=”12.0” />
辅助方法还允许你提供明确的值以避免自动数据查找,一些时候明确的方法是必须的:
public ActionResult Edit(int id) { var album = storeDB.Albums.Single(a => a.AlbumId == id); ViewBag.Genres = new SelectList(storeDB.Genres.OrderBy(g => g.Name), ”GenreId”, ”Name”, album.GenreId); return View(album); }
@Html.TextBox(“Title”, Model.Title)
@{
ViewBag.Title = “Edit - “ + Model.Title;
}
如果你调用TextBox helper时只提供了一个字符串参数"Title",那么helper会首先到ViewBag里面查找名为Title的值(helpers会在检查强类型模型前先查找ViewBag)。
强类型 Helpers
如果你不喜欢通过字符串值从view data中查找值,那么你可以试试MVC提供的强类型helpers。使用它们,你需要通过一个lambda表达式来定义模型属性。如下代码所示:
@using (Html.BeginForm()) { @Html.ValidationSummary(excludePropertyErrors: true) <fieldset> <legend>Edit Album</legend> <p> @Html.LabelFor(m => m.GenreId) @Html.DropDownListFor(m => m.GenreId, ViewBag.Genres as SelectList) </p> <p> @Html.TextBoxFor(m => m.Title) @Html.ValidationMessageFor(m => m.Title) </p> <input type=”submit” value=”Save” /> </fieldset> }
用lambda表达式替换字符串有几个好处:
1.智能提示支持
2.易于重构(如果你改变了model的属性值,VS会自动改变视图里面的相应代码)。
Helpers and Model Metadata
Helpers所做的不单单是在ViewData中查找数据;它们还会去查找可用的元数据。例如,专辑编辑表单中用于显示分类的Label helper:
@Html.Label(“GenreId”)
它输出的html如下:
<label for=”GenreId”>Genre</label>
Genre从哪冒出来的?首先helper会询问运行时是否存在GenreId的模型元数据,然后运行时就会提供Ablum模型的相关定制attribute信息(DisplayName):
[DisplayName(“Genre”)] public int GenreId { get; set; }
你在第4章学过的data annotations对helpers有着巨大的影响。因为helpers构建的HTML是基于annotations提供的元数据的。
Templated Helpers
模板 helpers包括:Html.Display,Html.Editor,(强类型:Html.DisplayFor,Html.EditorFor)。
举个例子,Html.TextBoxFor helper呈现如下的HTML:
<input id=”Title” name=”Title” type=”text” value=”For Those About To Rock We Salute You” />
你可以用EditorFor来实现同样的功能
@Html.EditorFor(m => m.Title)
你还可以通过数据注释(data annotations)来改变生成的HTML:
[Required(ErrorMessage = “An Album Title is required”)] [StringLength(160)] [DataType(DataType.MultilineText)] public string Title { get; set; }
现在的EditorFor helper呈现如下HTML:
<textarea class=”text-box multi-line” id=”Title” name=”Title”> Let There Be Rock </textarea>
其他的模板 helpers还有DisplayForModel和EditorForModel,主要用于给实体模型生成HTML。使用它们,在为模型添加新属性的时候你就可以马上在UI看到改变而不需要去改变视图代码。
Helpers and ModelStates
所有用于显示表单值的helpers都与ModelState有着相互作用。记住,ModelState是模型绑定的副产物,它包含了所有检测模型时产生的验证信息。模型状态中还包含用户提交的原始数据。
Helpers在呈现表单项时会自动在模型状态字典里面查找相应的值。helpers以表达式名为关键字去模型状态字典中查找相应的键值,并用查找到的值替换掉视图数据。
OTHER INPUT HELPERS
Html.Hidden
@Html.Hidden(“wizardStep”, “1”)
<input id=”wizardStep” name=”wizardStep” type=”hidden” value=”1” />
@Html.HiddenFor(m => m.WizardStep)
Html.Password
与TextBox类似,区别在于它不保留提交的数据以及使用密码显示
@Html.Password(“UserPassword”)
<input id=”UserPassword” name=”UserPassword” type=”password” value=”” />
@Html.PasswordFor(m => m.UserPassword)
Html.RadioButton
@Html.RadioButton(“color”, “red”) @Html.RadioButton(“color”, “blue”, true) @Html.RadioButton(“color”, “green”) <input id=”color” name=”color” type=”radio” value=”red” /> <input checked=”checked” id=”color” name=”color” type=”radio” value=”blue” /> <input id=”color” name=”color” type=”radio” value=”green” />
@Html.RadioButtonFor(m => m.GenreId, “1”) Rock
@Html.RadioButtonFor(m => m.GenreId, “2”) Jazz
@Html.RadioButtonFor(m => m.GenreId, “3”) Pop
Html.CheckBox
这个helper比较独特,它会输出两个元素。因为只有当checkbox为选中状态时浏览器才会将它的值提交上去。加上hidden则确保checkbox没选中的情况也有提交值。
@Html.CheckBox(“IsDiscounted”) <input id=”IsDiscounted” name=”IsDiscounted” type=”checkbox” value=”true” /> <input name=”IsDiscounted” type=”hidden” value=”false” />
RENDERING HELPERS
Html.ActionLink
1.链接至同个控制器下的action:
@Html.ActionLink(“Link Text”, “AnotherAction”) <a href=”/Home/AnotherAction”>LinkText</a>
2.链接至不同控制器下的action(注意不控制器名不需要加上"Controller"后缀):
@Html.ActionLink(“Link Text”, “Index”, “ShoppingCart”)
3.给链接添加自定义参数
@Html.ActionLink(“Edit link text”, “Edit”, “StoreManager”, new {id=10720}, null)
Html.RouteLink
@Html.RouteLink(“Link Text”, new {action=”AnotherAction”})
URL Helpers
用于生成URL
Url.Action
<span> @Url.Action(“Browse”, “Store”, new { genre = “Jazz” }, null) </span> The result will be the following HTML: <span> /Store/Browse?genre=Jazz </span>
Url.RouteUrl
与RouteLink类似,只有一个路由名称的参数。
Url.Content
能够将相对地址转换成绝对地址
<script src=”@Url.Content(“~/Scripts/jquery-1.5.1.min.js”)” type=”text/javascript”></script>
Html.Partial and Html.RenderPartial
Partial helper用于呈现局部(partial)视图。
注意不需要为视图定义路径或扩展名,运行时会在所有可用的视图引擎中查找相应的视图。
@Html.Partial(“AlbumDisplay”)
RenderPartial helper和Partial相似,但它是直接在反应流中输出的。你必须将RenderPartial置于代码块中。下面的代码输出的html是一样的:
@{Html.RenderPartial(“AlbumDisplay “); }
@Html.Partial(“AlbumDisplay “)
那么究竟使用哪个好呢?
一般来说你会选择Partial因为它比较方便。然而,RenderPartial在性能方面略胜一筹。因为它是直接在响应流中输出的(不过只有在访问量比较大的站点上才能看出它们的区别)。
Html.Action and Html.RenderAction
比起Partial,Action更具灵活性和可重用性,因为它能使用一个独立的控制器上下文以及构建一个不同模型。
Action和RenderAction的区别仅在于RenderAction直接在响应中输出(有略微的性能优势)。
public class MyController { public ActionResult Index() { return View(); } [ChildActionOnly] public ActionResult Menu() { var menu = GetMenuFromSomewhere(); return PartialView(menu); } }
@model Menu <ul> @foreach (var item in Model.MenuItem) { <li>@item</li> } </ul>
<html> <head><title>Index with Menu</title></head> <body> @Html.Action(“Menu”) <h1>Welcome to the Index View</h1> </body> </html>
注意Menu action标注了ChildActionOnlyAttribute。这个attribute的作用是防止直接通过URL执行该action。只有通过Action或RenderAction才能调用该action。该attribute不是必须的,但通常建议在child actions加上它。
在ControllerContext还有一个新的属性叫IsChildAction。当action是通过Action或RenderAction调用的,该值就是true;由URL调用的则是false。一些action filters同时拥有多个不同的child actions(比如authorizeAttribute和OutputCacheAttribute)。
给RenderAction传值
public class MenuOptions { public int Width { get; set; } public int Height { get; set; } }
[ChildActionOnly] public ActionResult Menu(MenuOptions options) { return PartialView(options); }
@Html.Action(“Menu”, new {
options = new MenuOptions { Width=400, Height=500} })
配合使用ActionName Attribute
[ChildActionOnly] [ActionName(“CoolMenu”)] public ActionResult Menu(MenuOptions options) { return PartialView(options); }
这时你在调用时应使用CoolMenu而不是Menu。
SUMMARY
在章中,我们学习了如何为网站构建表单,以及一些HTMl helper的用法,如何使用helpers来帮你生成你想要的代码。
FIN
浙公网安备 33010602011771号