5.1 表单使用
5.1.1 action 和 method 特性
<form action="/Home/Index">
<input name="q" type="text"/>
<input value="提交" type="submit" />
</form>
如果没有 method 默认是: get 方法。
5.1.2 GET 方法还是 POST 方法
get 请求的所有参数都在URL中,因此可以为GET请求建立书签。除此之外,还可以保留所有的表单输入值。
因为GET不会改变服务器上的状态,所以客户端可以向服务端重复发送GET请求而不会产生负面影响。
通常在Web程序中,GET 请求用于读操作,POST 请求用于写操作(通常包括更新,创建和删除)。
<form action="/Home/Index" method="get">
<input name="q" type="text"/>
<input value="提交" type="submit" />
</form>
BeginForm Html 辅助方法
@using (Html.BeginForm("Search","Home",FormMethod.Get)) { <input name="q" type="text"/> <input value="提交" type="submit" />
}
|
BeginForm Html 的辅助方法利用路由引擎找到 HomeController 控制器的 Search 操作。它在后台使用 GetVirtualPath 方法,该方法在 Routetable 的 Routes 属性中——在 global.asax 中,应用程序注册所有路由的位置。
public class RouteTable
{
// 摘要:
// 获取从 System.Web.Routing.RouteBase 类派生的对象的集合。
// 返回结果:
// 包含集合中的所有路由的对象。
public static RouteCollection Routes { get; }
}
不采用HTML辅助方法,将编写所有代码:
@{
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 name="q" type="text" />
<input value="提交" type="submit" />
</form>
5.2 HTML辅助方法
5.2.1 自动编码
本章许多辅助方法都可以输出模型值。所有这些输出模型值的方法都会在渲染前,对值进行HTML编码。
@Html.TextArea("text","hello <br/> world");
TextArea 辅助方法的第二个参数是要渲染的值。
<textarea cols="20" id="text" name="text" rows="2">
hello <br/> world
</textarea>
5.2.2 辅助方法的使用(匿名对象 htmlAttributes,属性@class = "editForm",连字符data_validatable = true)
保护代码的同时,辅助方法给出了适当的控制。为了展示辅助方法的作用,下列给出 BeginForm 另外一个重载版本:
@using (Html.BeginForm("Search", "Home", FormMethod.Get,new {target ="_blank"}))
{
<input name="q" type="text" />
<input value="提交" type="submit" />
}
// 参数:
// actionName:
// 操作方法的名称。
//
// controllerName:
// 控制器的名称。
//
// method:
// 用于处理窗体的 HTTP 方法(GET 或 POST)。
//
// htmlAttributes:
// 一个对象,其中包含要为该元素设置的 HTML 特性。
public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, FormMethod method, object htmlAttributes);
|
向 BeginForm 方法的 htmlAttribute 参数传递一个匿名类型的对象,在MVC框架重载版本中,几乎每一个HTML辅助方法都包含 htmlAttribute 参数,有时发现某些重载版本中 htmlAttribte 参数类型是 IDctionary<string,object> 。辅助方法利用字典条目创建辅助方法生成元素的特性。
<form action="/Home/Search" method="get" target="_blank">
设置元素的 class 特性就要求匿名类型对象上必须有一个名为 class 的属性,或者值的字典中有一个 class 的键。在字典中有一个“class”键值不是问题,问题在对象中有一个 class 的属性。
因为 class 是 C# 的关键字,不能用作属性名称或标识符,所以要在c lass 前面加一个 @符号作为前缀:
@using (Html.BeginForm("Search", "Home", FormMethod.Get,new {target ="_blank",@class = "editForm"}))
{...}
结果:
<form action="/Home/Search" class="editForm" method="get" target="_blank">
另一个问题是将属性设置为带连字符的名称(像 data-val)。
所有 HTML 辅助方法在渲染 HTML 时会将属性名中的下划线转换为连字符。
@using (Html.BeginForm("Search", "Home", FormMethod.Get, new { target = "_blank", @class = "editForm", data_validatable = true }))
{...}
结果:
<form action="/Home/Search" class="editForm" data-validatable="True" method="get" target="_blank">
5.2.3 HTML 辅助方法工作原理
每一个 Razor 视图都继承了它们的基类的 Html 属性。Html 的属性类型是 System.Web.Mvc.HtmlHelper<T> 。
当方法名称左边有一个向下的蓝色箭头时,说明这个方法是一个扩展方法。
5.2.4 设置专辑编辑表单
@using (Html.BeginForm())
{
@Html.ValidationSummary(excludePropertyErrors:true)
<fieldset>
<legend>Edit Album</legend>
<p><input type="submit" value="Save"/></p>
</fieldset>
}
这段代码有两个辅助方法:
1.Html.BeginForm
这里不带参数的 BeginForm 向当前发送一个 POST 请求,如果响应了
<form action="/Home/Test" method="post">
2.Html.ValidationSummary(生成错误验证摘要)
ValidationSummary 用来显示 ModelState 字典中所有验证错误的无序列表。告知 ValidationSummary 方法只显示 ModelState 中与模型本身有关错误,而不显示那些与具体模型属性相关的错误。
ModelState.AddModelError("TermsAccepted", "You must accept the terms");
5.2.5 添加输入元素
1.Html.TextBox 和 Html.TextArea
Html.TextBox 会渲染一个 type 特性为 text 的 input 标签。
@Html.TextBox("Title",Model.Title)
生成的HTML:<input id="Title" name="Title" type="text" value="Caravan">
@Html.TextArea("text","hello <br/> world")
生成的HTML:<textarea cols="20" id="text" name="text" rows="2">hello <br/> world</textarea>
@Html.TextArea("text", "hello <br/> world", 10, 80, null)
生成的HTML:<textarea cols="80" id="text" name="text" rows="10">hello <br/> world</textarea>
2.Html.Lable
返回一个<lable>元素,并使用 String 类型参数决定渲染的文本和 for 特性值。(提示:"for" 属性可把 label 绑定到另外一个元素。请把 "for" 属性的值设置为相关元素的 id 属性的值。)
@Html.Label("GenreId")
生成的HTML:<label for="GenreId">GenreId</label>
3.Html.DropDownList 和 Html.ListBox
DropDownList(单选) 和 ListBox(多选) 都返回一个 <select/> 元素。
下拉列表需要一个包含所有可选项的 SelectListItem 对象集合,其中每一个 SelectListItem 对象包含 Text , Value 和 Selected 三个属性。也可以使用框架中的 SelectList 或 MultiSelectList 辅助方法来构建。这些类可以查看任意类型的 IEnumerable 对象并将其转换为 SelectListItem 对象的序列。
/// <summary>
/// 使用列表的指定项、数据值字段、数据文本字段和选定的值来初始化 System.Web.Mvc.SelectList 类的新实例
/// </summary>
/// <param name="items">各个项</param>
/// <param name="dataValueField">数据值字段</param>
/// <param name="dataTextField">数据文本字段</param>
/// <param name="selectedValue">选定的值</param>
public SelectList(IEnumerable items, string dataValueField, string dataTextField, object selectedValue);
例如,StoreManager 控制器中的 Edit 操作:
后台:
public ActionResult CreateMyTest(int id = 0)
{
Album album = db.Albums.Find(id);
if (album == null)
{
return HttpNotFound();
}
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);
return View(album);
}
前台:
@Html.DropDownList("GenreId", "请选择")
生成的HTML:
<select id="GenreId" name="GenreId">
<option value="">请选择</option>
<option selected="selected" value="1">Al Di Meola</option>
</select>
|
4.Html.ValidationMessage
当 ModelState 字典中的某一特定字段出现错误时,可以使用 ValidationMessage 辅助方法显示相应的错误提示消息。下面故意在模型状态中为 Title 属性添加一个错误:
public ActionResult CreateMyTest(int id = 0)
{
Album album = db.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>
也可以调用 ValidationMessage 重写方法来重写错误提示:@Html.ValidationMessage("Title","Something is wrong with your title")
5.2.6 辅助方法、模型和视图数据
辅助方法如 Html.TextBox 和 Html.DropDownList(以及其他所有表单辅助方法) 检查 ViewData 对象以获取要显示的当前值(在 ViewBag 对象中所有值也可以通过 ViewData 得到)
public ActionResult Test2(int id)
{
ViewBag.Price = 10;
return View();
}
视图中,使用 ViewBag 中的值为 TextBox 辅助方法命名,显示价格的文本框:@Html.TextBox("Price")
<input data-val="true" id="Price" name="Price" type="text" value="10">
当辅助方法查看 ViewData 内容时,能看到其中对象属性。下面修改控制器:
public ActionResult Test2(int id)
{
ViewBag.Album = new Album { Price = 11 };
ViewBag.Price = 10;
return View();
}
视图修改:
@Html.TextBox("Album.Price")
输出HTML:
<input data-val="true" id="Album_Price" name="Album.Price" type="text" value="11">
如果 ViewData 没有匹配 “Album.Price” 的值,那辅助方法将尝试查找与第一个点之前那部分名称(Album)匹配的值。换言之,就是找一个 Album 类型的对象。然后估测名称中剩余部分(Price),并找到相应的值。
注意得到 input 元素的 id 特性值使用下划线代替了点(但name特性依然使用点)。因为 id 特性中包含点是非法的。因此,运行时用静态属性 HtmlHelper.IdAttributeDotReplacement 的值代替了点。如果没有有效的 id 特性,就无法执行带有 javascript 库的客户端脚本。
5.2.7 强类型辅助方法
如果不适应从视图数据中提取值,可以使用 MVC 提供的强类型辅助分类方法。只需要提供一个 lambda 表达式来指定要渲染的模型属性。
@model MVC4.Models.Album
添加了模型指令,可以使用下面的代码:
@Html.LabelFor(m=>m.GenreId)
@Html.DropDownListFor(m => m.GenreId, ViewBag.Genres as SelectList, "请选择")
静观代码生成与前面同样的 HTML标记,但用 lambda 表达式代替字符串有其他好处,包括智能感应、编译时检查和轻松的代码重构。
5.2.8 辅助方法和模型元数据
辅助方法不仅查看 VIewData 内部数据,也利用可得到的模型元数据。
@Html.LabelFor(m=>m.GenreId)
文本生成:<label for="GenreId">流派</label>
文本“流派”从哪里来的?当辅助方法询问运行时是否有 GenreId 的可用模型元数据时,运行时从装饰 Album 模型的 DIsplayName 特性中获取的信息。
[DisplayName("流派")]
public virtual int GenreId { get; set; }
5.2.9 模版辅助方法
MVC 中的模版辅助方法利用元数据和模版构建 HTML 。
元数据包括关羽模型值(它的名称和类型)的信息和(通过数据注解或自定义提供器添加的)模型元数据。模版辅助方法有 Html.Display 和 Html.Editor ,以及分别与它们对应的强类型方法 Html.DisplayFor 和 Html.EditorFor ,还有它们对应到完整模型 Html.DisplayForModel 和 Html.EditorModel 。
例如 Html.TextBoxFor 辅助方法为某个专辑的 Title 属性生成HTML标记:
@Html.TextBoxFor(m => m.Title)
<input id="Title" name="Title" type="text" value="Caravan">
也可以使用 EditorFor 方法取代:
@Html.EditorFor(m => m.Title)
下面为 Title 属性添加一个 DataType 注解:
[Required(ErrorMessage ="An Album Title is required")]
[StringLength(160)]
[DataType(DataType.MultilineText)]
public virtual string Title { get; set; }
生成的HTML:
<textarea class="text-box multi-line" data-val="true" data-val-length="字段 Title 必须是最大长度为 160 的字符串。" data-val-length-max="160" data-val-required="An Album Title is required" id="Title" name="Title">
Caravan
</textarea>
5.2.10 辅助方法和 ModelState
用来显示表单的值的所有辅助方法需要与 ModelState 交互。
用来渲染表单字段的辅助方法自动在 ModelState 字典中查找它们的当前值。辅助方法使用名称表达式作为键,在 ModelState 字典进行查找。如果查找的值已在 ModelState 中,辅助方法就用 ModelState 的值替换视图数据中的当前值。
模型绑定失败后, ModelState 查找表中允许保存“坏”值。例如,用户向 DateTime 属性编辑器中输入值 "abc",模型绑定就会失败,并且“abc” 也会保存在模型状态相关属性中。为了在用户修改验证错误而重新渲染视图时,“abc”值依然出现在 DateTime 编辑器中,可让用户看到刚才尝试的错误文本并允许他们修改。
当 ModelState 包含某个属性的错误时,与错误相关的表单辅助方法除了显示渲染指定 CSS 类之外,还会渲染 input-validation-error CSS 类。
5.3 其他输入辅助方法
5.3.1 Html.Hidden
@Html.Hidden("wizard", "值")
生成的Html:
<input type="hidden" id="wizard" name="wizard" value="值" />
5.3.2 Html.passwrod
@Html.Password("wizard")
生成的Html:
<input type="password" id="wizard" name="wizard" />
5.2.3 Html.RadioButtion
单选按钮一般组合起一起用。
@Html.RadioButton("color", "red")
@Html.RadioButton("color", "blue",true)
@Html.RadioButton("color", "green")
生成的HTML:
<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">
5.2.4 Html.CheckBox
唯一渲染两个输入元素的方法
@Html.CheckBox("IsDiscuounted")
生成的Html:
<input id="IsDiscuounted" name="IsDiscuounted" type="checkbox" value="true">
<input name="IsDiscuounted" type="hidden" value="false">
5.4 渲染辅助方法
5.4.1 Html.ActionLink 和 Html.RouteLink
1.Html.ActionLink能够渲染一个超链接。
@Html.ActionLink("text", "index")
生成HTML:
<a href="/home/index">text</a>
2.当需要指向一个不同控制器的时候
@Html.ActionLink("index", "MenuList","Menu")
生成的HTML:
<a href="/Menu/MenuList">index</a>
3.传递参数,内置的 ActionLink没有提供处理版本。
但是,其中一个版本允许向它传递一个 RouteValueDictionary 类型对象;另外一个版本允许给 routeValues 参数传递一个对象(通常是匿名类型的)。
例如,构建一个指向ID号为10720的专辑编辑页面的链接
@Html.ActionLink("Edit link text", "Edit", "StoreManager", new { id = 10720 }, null)
上面重载最后一个参数是 htmlAttributes。传递了一个 null (实际上没有设置 HTML 元素上的任何特性值)。尽管未设置任何特性,但是为了调用 ActionLink 这个重载方法,必须传递一个参数。
生成的HTML:
<a href="/StoreManager/Edit/10720">Edit link text</a>
4.尽管 RouteLink 方法和 ActionLink 方法遵循相同模式,但 RouteLink 只接收路由名称,而不能接收控制器名称和操作名称。
例如,演示 ActionLink 的第一个例子也可以用下面代码,
@Html.RouteLink("Link Text2",new{action="AnotherAction"})
生成HTML:
<a href="/Home/AnotherAction">Link Text2</a>
5.4.2 URL 辅助方法
1 Url.Action
Action 方法与 ActionLink 相似,但它不返回锚标签。
<span>
@Url.Action("browse", "Store", new { genre = "Jazz" }, null)
</span>
生成的HTML:
<span>
/Store/browse?genre=Jazz
</span>
2 Url.Content
Content 方法特别有用,因为它可以把应用程序的相对路径换成绝对路径。
<script type="text/javascript" src="@Url.Content("~/Scripts/jquery-1.10.2.js")"></script>
3 Url.RouteUrl
RouteUrl 辅助方法与 Action 方法遵循同样的模式,但与 RouteLink 一样,只接收路由名称,而不接收控制器和操作名称。
5.4.3 Html.Partial 和 Html.RenderPartial
1.Html.Partial
Partial有4个重载版本
public static MvcHtmlString Partial(this HtmlHelper htmlHelper, string partialViewName);
public static MvcHtmlString Partial(this HtmlHelper htmlHelper, string partialViewName, object model);
public static MvcHtmlString Partial(this HtmlHelper htmlHelper, string partialViewName, ViewDataDictionary viewData);
public static MvcHtmlString Partial(this HtmlHelper htmlHelper, string partialViewName, object model, ViewDataDictionary viewData);
这里没必要为视图指定路径和文件扩展名,因为运行时定位部分视图与定位正常视图使用的逻辑相同。
@Html.Partial("MenuForm")
2.Html.RenderPartial
RenderPartial 与 Partial 非常相似,但 RenderPartial 不返回字符串,而是直接写入响应输出流。
出于这个原因,必须把 RenderPartial 放入代码块中,而不能放入代码表达式中。
(1)错误写法:
@Html.RenderPartial("MenuList")
(2)正确写法:
@{Html.RenderPartial("MenuList");}
5.4.4 Html.Action 和 Html.RederAction
1.首先看一下它们的对等关系
@Html.Partial 对应 @{Html.RenderPartial();}
@Html.Action 对应 @{Html.RenderAction();}
2.Action 加载方法的视图,执行 Controller → Model → View 的顺序,然后把产生的页面带回到原来的View中再回传。而Partial直接加载视图文件内容
3.@Html.Partial 可以直接提供用户控件名作为参数,而 Html.Action 需要有对应的 Action ,在 Action 内部返回 PartailResult (即retun PartialView()) 。