《ASP.NET MVC高级编程(4版)》读书笔记(5)表单和HTML辅助方法


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 &lt;br/&gt; 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.Getnew { 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 &lt;br/&gt; world</textarea>

@Html.TextArea("text""hello <br/> world", 10, 80, null)  
生成的HTML:<textarea cols="80" id="text" name="text" rows="10">hello &lt;br/&gt; 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.GenreIdViewBag.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 { getset; }  

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 { getset; }

生成的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()) 。
































posted @ 2016-12-28 20:15  【唐】三三  阅读(565)  评论(1编辑  收藏  举报