ASP.NET Core 表单中的标记帮助程序Tag Helpers in forms in ASP.NET Core

本文内容

作者:Rick AndersonN. Taylor MullenDave PaquetteJerrie Pelser

本文档演示如何使用表单和表单中常用的 HTML 元素。HTML Form 元素提供 Web 应用用于向服务器回发数据的主要机制。本文档的大部分内容介绍标记帮助程序及其如何帮助高效创建可靠的 HTML 表单。建议在阅读本文档前先阅读标记帮助程序简介

在很多情况下,HTML 帮助程序为特定标记帮助程序提供了一种替代方法,但标记帮助程序不会替代 HTML 帮助程序,且并非每个 HTML 帮助程序都有对应的标记帮助程序,认识到这点也很重要。如果存在 HTML 帮助程序替代项,文中会提到。

表单标记帮助程序The Form Tag Helper

表单标记帮助程序:

  • 为 MVC 控制器操作或命名路由生成 HTML

    action 属性值

  • 生成隐藏的请求验证令牌,防止跨站点请求伪造(在 HTTP Post 操作方法中与 [ValidateAntiForgeryToken] 属性配合使用时)

  • 提供 asp-route-<Parameter Name> 属性,其中 <Parameter Name> 添加到路由值。routeValuesHtml.BeginFormHtml.BeginRouteForm 参数提供类似的功能。

  • 具有 HTML 帮助程序替代项 Html.BeginFormHtml.BeginRouteForm


示例:

  1. <form asp-controller="Demo" asp-action="Register" method="post">
  2. <!-- Input and Submit elements -->
  3. </form>

上述表单标记帮助程序生成以下 HTML:

  1. <form method="post" action="/Demo/Register">
  2. <!-- Input and Submit elements -->
  3. <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
  4. </form>

MVC 运行时通过表单标记帮助程序属性 actionasp-controller 生成 asp-action 属性值。表单标记帮助程序还会生成隐藏的请求验证令牌,防止跨站点请求伪造(在 HTTP Post 操作方法中与 [ValidateAntiForgeryToken] 属性配合使用时)。保护纯 HTML 表单免受跨站点请求伪造的影响很难,但表单标记帮助程序可提供此服务。

使用命名路由Using a named route

asp-route 标记帮助程序属性还可为 HTML action 属性生成标记。具有名为 路由register的应用可将以下标记用于注册页:

  1. <form asp-route="register" method="post">
  2. <!-- Input and Submit elements -->
  3. </form>

Views/Account 文件夹中的许多视图(在新建使用个人用户帐户身份验证的 Web 应用时生成)包含 asp-route-returnurl 属性:

  1. <form asp-controller="Account" asp-action="Login"
  2. asp-route-returnurl="@ViewData["ReturnUrl"]"
  3. method="post" class="form-horizontal" role="form">

备注

使用内置模板时,returnUrl 仅会在用户尝试访问授权资源,但未验证身份或未获得授权的情况下自动填充。如果尝试执行未经授权的访问,安全中间件会使用 returnUrl 集将用户重定向至登录页。

窗体操作标记帮助程序The Form Action Tag Helper

窗体操作标记帮助程序在生成的 formaction<button …> 标记上生成 <input type="image" …> 属性。formaction 属性控制窗体在何处提交数据。它绑定到 类型的 <input>image 元素以及 <button> 元素。窗体操作标记帮助程序允许使用多个 AnchorTagHelper asp- 属性来控制为相应元素生成的 formaction 链接。

用于控制 值的受支持的 AnchorTagHelperformaction 属性:

Attribute说明
asp-controller控制器的名称。
asp-action操作方法的名称。
asp-area区域名称。
asp-pageRazor Page 的名称。
asp-page-handlerRazor Page 处理程序的名称。
asp-route路由的名称。
asp-route-{value}单个 URL 路由值。例如,asp-route-id="1234"
asp-all-route-data所有路由值。
asp-fragmentURL 片段。

提交到控制器示例Submit to controller example

选中输入或按钮时,下面的标记将窗体提交到 IndexHomeController 操作:

  1. <form method="post">
  2. <button asp-controller="Home" asp-action="Index">Click Me</button>
  3. <input type="image" src="..." alt="Or Click Me" asp-controller="Home"
  4. asp-action="Index">
  5. </form>

之前的标记将生成以下 HTML:

  1. <form method="post">
  2. <button formaction="/Home">Click Me</button>
  3. <input type="image" src="..." alt="Or Click Me" formaction="/Home">
  4. </form>

提交到页示例Submit to page example

以下标记将窗体提交到 About Razor Page:

  1. <form method="post">
  2. <button asp-page="About">Click Me</button>
  3. <input type="image" src="..." alt="Or Click Me" asp-page="About">
  4. </form>

之前的标记将生成以下 HTML:

  1. <form method="post">
  2. <button formaction="/About">Click Me</button>
  3. <input type="image" src="..." alt="Or Click Me" formaction="/About">
  4. </form>

提交到路由示例Submit to route example

请考虑使用 /Home/Test 终结点:

  1. public class HomeController : Controller
  2. {
  3. [Route("/Home/Test", Name = "Custom")]
  4. public string Test()
  5. {
  6. return "This is the test page";
  7. }
  8. }

以下标记将窗体提交到 /Home/Test 终结点。

  1. <form method="post">
  2. <button asp-route="Custom">Click Me</button>
  3. <input type="image" src="..." alt="Or Click Me" asp-route="Custom">
  4. </form>

之前的标记将生成以下 HTML:

  1. <form method="post">
  2. <button formaction="/Home/Test">Click Me</button>
  3. <input type="image" src="..." alt="Or Click Me" formaction="/Home/Test">
  4. </form>

输入标记帮助程序The Input Tag Helper

输入标记帮助程序将 HTML <input> 元素绑定到 Razor 视图中的模型表达式。

语法:

  1. <input asp-for="<Expression Name>">

输入标记帮助程序:

  • id 属性中指定的表达式名称生成 nameasp-for HTML 属性。asp-for="Property1.Property2" 等效于 m => m.Property1.Property2。表达式的名称用于 asp-for 属性值。有关其他信息,请参阅表达式名称部分。

  • 根据模型类型和应用于模型属性的type数据注释特性设置 HTML 特性值

  • 如果已经指定,不会覆盖 HTML type 属性值

  • 通过应用于模型属性的数据注释特性生成 HTML5 验证特性

  • 具有与 Html.TextBoxForHtml.EditorFor 重叠的 HTML 帮助程序功能。有关详细信息,请参阅输入标记帮助程序的 HTML 帮助程序替代项部分。

  • 提供强类型化。如果属性的名称更改,但未更新标记帮助程序,则会收到类似如下内容的错误:

  1. An error occurred during the compilation of a resource required to process
  2. this request. Please review the following specific error details and modify
  3. your source code appropriately.
  4. Type expected
  5. 'RegisterViewModel' does not contain a definition for 'Email' and no
  6. extension method 'Email' accepting a first argument of type 'RegisterViewModel'
  7. could be found (are you missing a using directive or an assembly reference?)

Input 标记帮助程序根据 .NET 类型设置 HTML type 属性。下表列出一些常见的 .NET 类型和生成的 HTML 类型(并未列出每个 .NET 类型)。

.NET 类型输入类型
Booltype="checkbox"
Stringtype="text"
DateTimetype="datetime-local"
Bytetype="number"
Inttype="number"
Single、Doubletype="number"

下表显示输入标记帮助程序会映射到特定输入类型的一些常见数据注释属性(并未列出每个验证属性):

Attribute输入类型
[EmailAddress]type="email"
[Url]type="url"
[HiddenInput]type="hidden"
[Phone]type="tel"
[DataType(DataType.Password)]type="password"
[DataType(DataType.Date)]type="date"
[DataType(DataType.Time)]type="time"

示例:

  1. using System.ComponentModel.DataAnnotations;
  2. namespace FormsTagHelper.ViewModels
  3. {
  4. public class RegisterViewModel
  5. {
  6. [Required]
  7. [EmailAddress]
  8. [Display(Name = "Email Address")]
  9. public string Email { get; set; }
  10. [Required]
  11. [DataType(DataType.Password)]
  12. public string Password { get; set; }
  13. }
  14. }
  1. @model RegisterViewModel
  2. <form asp-controller="Demo" asp-action="RegisterInput" method="post">
  3. Email: <input asp-for="Email" /> <br />
  4. Password: <input asp-for="Password" /><br />
  5. <button type="submit">Register</button>
  6. </form>

上述代码生成以下 HTML:

  1. <form method="post" action="/Demo/RegisterInput">
  2. Email:
  3. <input type="email" data-val="true"
  4. data-val-email="The Email Address field is not a valid email address."
  5. data-val-required="The Email Address field is required."
  6. id="Email" name="Email" value=""><br>
  7. Password:
  8. <input type="password" data-val="true"
  9. data-val-required="The Password field is required."
  10. id="Password" name="Password"><br>
  11. <button type="submit">Register</button>
  12. <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
  13. </form>

应用于 EmailPassword 属性的数据注释在模型中生成元数据。输入标记帮助程序使用模型元数据并生成 HTML5 data-val-* 属性(请参阅模型验证)。这些属性描述要附加到输入字段的验证程序。这样可以提供非介入式 HTML5 和 jQuery 验证。非引人注目特性的格式 data-val-rule="Error Message",其中 rule 是验证规则的名称(如 data-val-requireddata-val-emaildata-val-maxlength等)如果属性中提供错误消息,则该消息将显示为 data-val-rule 特性的值。还有表单 data-val-ruleName-argumentName="argumentValue" 的属性,这些属性提供有关规则的其他详细信息,例如,data-val-maxlength-max="1024"

输入标记帮助程序的 HTML 帮助程序替代项HTML Helper alternatives to Input Tag Helper

Html.TextBoxHtml.TextBoxForHtml.EditorHtml.EditorFor 与输入标记帮助程序的功能存在重叠。输入标记帮助程序会自动设置 type 属性;而 Html.TextBoxHtml.TextBoxFor 不会。Html.EditorHtml.EditorFor 处理集合、复杂对象和模板;而输入标记帮助程序不会。输入标记帮助程序、Html.EditorForHtml.TextBoxFor 是强类型(使用 lambda 表达式);而 Html.TextBoxHtml.Editor 不是(使用表达式名称)。

HtmlAttributesHtmlAttributes

@Html.Editor()@Html.EditorFor() 在执行其默认模板时使用名为 ViewDataDictionary 的特殊 htmlAttributes 条目。此行为可选择使用 additionalViewData 参数增强。键“htmlAttributes”区分大小写。键“htmlAttributes”的处理方式与传递到输入帮助程序的 htmlAttributes 对象(例如 @Html.TextBox())的处理方式类似。

  1. @Html.EditorFor(model => model.YourProperty,
  2. new { htmlAttributes = new { @class="myCssClass", style="Width:100px" } })

表达式名称Expression names

asp-for 属性值是 ModelExpression,并且是 lambda 表达式的右侧。因此,asp-for="Property1" 在生成的代码中变成 m => m.Property1,这也是无需使用 Model 前缀的原因。“@”字符可用作内联表达式的开头,并移到 m. 前面:

  1. @{
  2. var joe = "Joe";
  3. }
  4. <input asp-for="@joe">

生成以下 HTML:

  1. <input type="text" id="joe" name="joe" value="Joe">

使用集合属性时,asp-for="CollectionProperty[23].Member"asp-for="CollectionProperty[i].Member" 具有值 i 时生成与 23 相同的名称。

在 ASP.NET Core MVC 计算 ModelExpression 的值时,它会检查多个源,包括 ModelState<input type="text" asp-for="@Name"> 为例。计算出的 value 属性是第一个非 null 值,属于:

  • 带有“Name”键的 ModelState 条目。
  • Model.Name 表达式的结果。

导航子属性Navigating child properties

还可使用视图模型的属性路径导航到子属性。设想一个包含子 Address 属性的更复杂的模型类。

  1. public class AddressViewModel
  2. {
  3. public string AddressLine1 { get; set; }
  4. }
  1. public class RegisterAddressViewModel
  2. {
  3. public string Email { get; set; }
  4. [DataType(DataType.Password)]
  5. public string Password { get; set; }
  6. public AddressViewModel Address { get; set; }
  7. }

在视图中,绑定到 Address.AddressLine1

  1. @model RegisterAddressViewModel
  2. <form asp-controller="Demo" asp-action="RegisterAddress" method="post">
  3. Email: <input asp-for="Email" /> <br />
  4. Password: <input asp-for="Password" /><br />
  5. Address: <input asp-for="Address.AddressLine1" /><br />
  6. <button type="submit">Register</button>
  7. </form>

Address.AddressLine1 生成以下 HTML:

  1. <input type="text" id="Address_AddressLine1" name="Address.AddressLine1" value="">

表达式名称和集合Expression names and Collections

包含 Colors 数组的模型示例:

  1. public class Person
  2. {
  3. public List<string> Colors { get; set; }
  4. public int Age { get; set; }
  5. }

操作方法:

  1. public IActionResult Edit(int id, int colorIndex)
  2. {
  3. ViewData["Index"] = colorIndex;
  4. return View(GetPerson(id));
  5. }

以下 Razor 显示如何访问特定 Color 元素:

  1. @model Person
  2. @{
  3. var index = (int)ViewData["index"];
  4. }
  5. <form asp-controller="ToDo" asp-action="Edit" method="post">
  6. @Html.EditorFor(m => m.Colors[index])
  7. <label asp-for="Age"></label>
  8. <input asp-for="Age" /><br />
  9. <button type="submit">Post</button>
  10. </form>

Views/Shared/EditorTemplates/String.cshtml 模板:

  1. @model string
  2. <label asp-for="@Model"></label>
  3. <input asp-for="@Model" /> <br />

使用 List<T> 的示例:

  1. public class ToDoItem
  2. {
  3. public string Name { get; set; }
  4. public bool IsDone { get; set; }
  5. }

以下 Razor 演示如何循环访问集合:

  1. @model List<ToDoItem>
  2. <form asp-controller="ToDo" asp-action="Edit" method="post">
  3. <table>
  4. <tr> <th>Name</th> <th>Is Done</th> </tr>
  5. @for (int i = 0; i < Model.Count; i++)
  6. {
  7. <tr>
  8. @Html.EditorFor(model => model[i])
  9. </tr>
  10. }
  11. </table>
  12. <button type="submit">Save</button>
  13. </form>

Views/Shared/EditorTemplates/ToDoItem.cshtml 模板:

  1. @model ToDoItem
  2. <td>
  3. <label asp-for="@Model.Name"></label>
  4. @Html.DisplayFor(model => model.Name)
  5. </td>
  6. <td>
  7. <input asp-for="@Model.IsDone" />
  8. </td>
  9. @*
  10. This template replaces the following Razor which evaluates the indexer three times.
  11. <td>
  12. <label asp-for="@Model[i].Name"></label>
  13. @Html.DisplayFor(model => model[i].Name)
  14. </td>
  15. <td>
  16. <input asp-for="@Model[i].IsDone" />
  17. </td>
  18. *@

应尽量在 foreachasp-for 等效上下文中使用值 Html.DisplayFor一般情况下,for 优于 foreach(如果情况允许使用的话),因为它不需要分配枚举器,但在 LINQ 表达式中评估索引器的成本高昂,应最大限度地减少使用它。

备注

上述带有注释的示例代码演示如何将 lambda 表达式替换为 @ 运算符来访问列表中的每个 ToDoItem

文本区标记帮助程序The Textarea Tag Helper

Textarea Tag Helper 标记帮助程序类似于输入标记帮助程序。

  • 通过模型为 id``nametextarea> 元素生成 < 和 属性以及数据验证属性。

  • 提供强类型化。

  • HTML 帮助程序替代项:Html.TextAreaFor

示例:

  1. using System.ComponentModel.DataAnnotations;
  2. namespace FormsTagHelper.ViewModels
  3. {
  4. public class DescriptionViewModel
  5. {
  6. [MinLength(5)]
  7. [MaxLength(1024)]
  8. public string Description { get; set; }
  9. }
  10. }
  1. @model DescriptionViewModel
  2. <form asp-controller="Demo" asp-action="RegisterTextArea" method="post">
  3. <textarea asp-for="Description"></textarea>
  4. <button type="submit">Test</button>
  5. </form>

生成以下 HTML:

  1. <form method="post" action="/Demo/RegisterTextArea">
  2. <textarea data-val="true"
  3. data-val-maxlength="The field Description must be a string or array type with a maximum length of &#x27;1024&#x27;."
  4. data-val-maxlength-max="1024"
  5. data-val-minlength="The field Description must be a string or array type with a minimum length of &#x27;5&#x27;."
  6. data-val-minlength-min="5"
  7. id="Description" name="Description">
  8. </textarea>
  9. <button type="submit">Test</button>
  10. <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
  11. </form>

标签标记帮助程序The Label Tag Helper

Label Tag Helper 通过纯 HTML 标签元素提供如下优势:

  • 可自动从 Display 属性中获取描述性标签值。预期的显示名称可能会随时间变化,Display 属性和标签标记帮助程序的组合会在其被使用的所有位置应用 Display

  • 源代码中的标记更少

  • 模型属性的强类型化。

示例:

  1. using System.ComponentModel.DataAnnotations;
  2. namespace FormsTagHelper.ViewModels
  3. {
  4. public class SimpleViewModel
  5. {
  6. [Required]
  7. [EmailAddress]
  8. [Display(Name = "Email Address")]
  9. public string Email { get; set; }
  10. }
  11. }
  1. @model SimpleViewModel
  2. <form asp-controller="Demo" asp-action="RegisterLabel" method="post">
  3. <label asp-for="Email"></label>
  4. <input asp-for="Email" /> <br />
  5. </form>

<label> 元素生成以下 HTML:

  1. <label for="Email">Email Address</label>

标签标记帮助程序生成“Email”的 for 属性值,即与 <input> 元素关联的 ID。标记帮助程序生成一致的 idfor 元素,方便将其正确关联。本示例中的描述来自 Display 属性。如果模型不包含 Display 特性,描述将为表达式的属性名称。

验证标记帮助程序The Validation Tag Helpers

有两个验证标记帮助程序。Validation Message Tag Helper(为模型中的单个属性显示验证消息)和 Validation Summary Tag Helper(显示验证错误的摘要)。Input Tag Helper 根据模型类的数据注释属性将 HTML5 客户端验证属性添加到输入元素中。同时在服务器上执行验证。验证标记帮助程序会在发生验证错误时显示这些错误消息。

验证消息标记帮助程序The Validation Message Tag Helper

  • HTML5 data-valmsg-for="property" 属性添加到 span 元素中,该元素会附加指定模型属性的输入字段中的验证错误消息。jQuery 会在发生客户端验证错误时在 <span> 元素中显示错误消息。

  • 还会在服务器上执行验证。客户端可能已禁用 JavaScript,一些验证仅可在服务器端执行。

  • HTML 帮助程序替代项:Html.ValidationMessageFor

Validation Message Tag Helper 与 HTML asp-validation-forspan 元素中的 属性配合使用。

  1. <span asp-validation-for="Email"></span>

验证消息标记帮助程序会生成以下 HTML:

  1. <span class="field-validation-valid"
  2. data-valmsg-for="Email"
  3. data-valmsg-replace="true"></span>

对于同一属性,通常在 Validation Message Tag Helper 标记帮助程序后使用 Input这样做可在导致错误的输入附近显示所有验证错误消息。

备注

必须拥有包含正确的 JavaScript 和 jQuery 脚本引用的视图才能执行客户端验证。有关详细信息,请参阅模型验证

发生服务器端验证错误时(例如,禁用自定义服务器端验证或客户端验证时),MVC 会将该错误消息作为 <span> 元素的主体。

  1. <span class="field-validation-error" data-valmsg-for="Email"
  2. data-valmsg-replace="true">
  3. The Email Address field is required.
  4. </span>

验证摘要标记帮助程序The Validation Summary Tag Helper

  • 针对具有 <div> 属性的 asp-validation-summary 元素

  • HTML 帮助程序替代项:@Html.ValidationSummary

Validation Summary Tag Helper 用于显示验证消息的摘要。asp-validation-summary 属性值可以是以下任意值:

asp-validation-summary显示的验证消息
ValidationSummary.All属性和模型级别
ValidationSummary.ModelOnly“模型”
ValidationSummary.None

示例Sample

在以下示例中,数据模型具有 DataAnnotation 属性,在 <input> 元素中生成验证错误消息。验证标记帮助程序会在发生验证错误时显示错误消息:

  1. using System.ComponentModel.DataAnnotations;
  2. namespace FormsTagHelper.ViewModels
  3. {
  4. public class RegisterViewModel
  5. {
  6. [Required]
  7. [EmailAddress]
  8. [Display(Name = "Email Address")]
  9. public string Email { get; set; }
  10. [Required]
  11. [DataType(DataType.Password)]
  12. public string Password { get; set; }
  13. }
  14. }
  1. @model RegisterViewModel
  2. <form asp-controller="Demo" asp-action="RegisterValidation" method="post">
  3. <div asp-validation-summary="ModelOnly"></div>
  4. Email: <input asp-for="Email" /> <br />
  5. <span asp-validation-for="Email"></span><br />
  6. Password: <input asp-for="Password" /><br />
  7. <span asp-validation-for="Password"></span><br />
  8. <button type="submit">Register</button>
  9. </form>

生成的 HTML(如果模型有效):

  1. <form action="/DemoReg/Register" method="post">
  2. <div class="validation-summary-valid" data-valmsg-summary="true">
  3. <ul><li style="display:none"></li></ul></div>
  4. Email: <input name="Email" id="Email" type="email" value=""
  5. data-val-required="The Email field is required."
  6. data-val-email="The Email field is not a valid email address."
  7. data-val="true"><br>
  8. <span class="field-validation-valid" data-valmsg-replace="true"
  9. data-valmsg-for="Email"></span><br>
  10. Password: <input name="Password" id="Password" type="password"
  11. data-val-required="The Password field is required." data-val="true"><br>
  12. <span class="field-validation-valid" data-valmsg-replace="true"
  13. data-valmsg-for="Password"></span><br>
  14. <button type="submit">Register</button>
  15. <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
  16. </form>

选择标记帮助程序The Select Tag Helper

  • 为模型属性生成 select 元素和关联的 option 元素。

  • 具有 HTML 帮助程序替代项 Html.DropDownListForHtml.ListBoxFor

Select Tag Helper asp-forselect 元素指定模型属性名称,asp-items 指定 option 元素。例如:

  1. <select asp-for="Country" asp-items="Model.Countries"></select>

示例:

  1. using Microsoft.AspNetCore.Mvc.Rendering;
  2. using System.Collections.Generic;
  3. namespace FormsTagHelper.ViewModels
  4. {
  5. public class CountryViewModel
  6. {
  7. public string Country { get; set; }
  8. public List<SelectListItem> Countries { get; } = new List<SelectListItem>
  9. {
  10. new SelectListItem { Value = "MX", Text = "Mexico" },
  11. new SelectListItem { Value = "CA", Text = "Canada" },
  12. new SelectListItem { Value = "US", Text = "USA" },
  13. };
  14. }
  15. }

Index 方法初始化 CountryViewModel,设置选定的国家/地区并将其传递到 Index 视图。

  1. public IActionResult Index()
  2. {
  3. var model = new CountryViewModel();
  4. model.Country = "CA";
  5. return View(model);
  6. }

HTTP POST Index 方法显示选定内容:

  1. [HttpPost]
  2. [ValidateAntiForgeryToken]
  3. public IActionResult Index(CountryViewModel model)
  4. {
  5. if (ModelState.IsValid)
  6. {
  7. var msg = model.Country + " selected";
  8. return RedirectToAction("IndexSuccess", new { message = msg });
  9. }
  10. // If we got this far, something failed; redisplay form.
  11. return View(model);
  12. }

Index 视图:

  1. @model CountryViewModel
  2. <form asp-controller="Home" asp-action="Index" method="post">
  3. <select asp-for="Country" asp-items="Model.Countries"></select>
  4. <br /><button type="submit">Register</button>
  5. </form>

生成以下 HTML(选择“CA”时):

  1. <form method="post" action="/">
  2. <select id="Country" name="Country">
  3. <option value="MX">Mexico</option>
  4. <option selected="selected" value="CA">Canada</option>
  5. <option value="US">USA</option>
  6. </select>
  7. <br /><button type="submit">Register</button>
  8. <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
  9. </form>

备注

不建议将 ViewBagViewData 与选择标记帮助程序配合使用。视图模型在提供 MVC 元数据方面更可靠且通常更不容易出现问题。

asp-for 属性值是特殊情况,它不要求提供 Model 前缀,但其他标记帮助程序属性需要该前缀(例如 asp-items

  1. <select asp-for="Country" asp-items="Model.Countries"></select>

枚举绑定Enum binding

通常可方便地将 <select>enum 属性配合使用并通过 SelectListItem 值生成 enum 元素。

示例:

  1. public class CountryEnumViewModel
  2. {
  3. public CountryEnum EnumCountry { get; set; }
  4. }
  5. }
  1. using System.ComponentModel.DataAnnotations;
  2. namespace FormsTagHelper.ViewModels
  3. {
  4. public enum CountryEnum
  5. {
  6. [Display(Name = "United Mexican States")]
  7. Mexico,
  8. [Display(Name = "United States of America")]
  9. USA,
  10. Canada,
  11. France,
  12. Germany,
  13. Spain
  14. }
  15. }

GetEnumSelectList 方法为枚举生成 SelectList 对象。

  1. @model CountryEnumViewModel
  2. <form asp-controller="Home" asp-action="IndexEnum" method="post">
  3. <select asp-for="EnumCountry"
  4. asp-items="Html.GetEnumSelectList<CountryEnum>()">
  5. </select>
  6. <br /><button type="submit">Register</button>
  7. </form>

可使用 Display 属性标记枚举器列表,以获取更丰富的 UI:

  1. using System.ComponentModel.DataAnnotations;
  2. namespace FormsTagHelper.ViewModels
  3. {
  4. public enum CountryEnum
  5. {
  6. [Display(Name = "United Mexican States")]
  7. Mexico,
  8. [Display(Name = "United States of America")]
  9. USA,
  10. Canada,
  11. France,
  12. Germany,
  13. Spain
  14. }
  15. }

生成以下 HTML:

  1. <form method="post" action="/Home/IndexEnum">
  2. <select data-val="true" data-val-required="The EnumCountry field is required."
  3. id="EnumCountry" name="EnumCountry">
  4. <option value="0">United Mexican States</option>
  5. <option value="1">United States of America</option>
  6. <option value="2">Canada</option>
  7. <option value="3">France</option>
  8. <option value="4">Germany</option>
  9. <option selected="selected" value="5">Spain</option>
  10. </select>
  11. <br /><button type="submit">Register</button>
  12. <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
  13. </form>

选项组Option Group

如果视图模型包含一个或多个 对象,则会生成 HTML <optgroup>SelectListGroup 元素。

CountryViewModelGroupSelectListItem 元素分组为“North America”组和“Europe”组:

  1. public class CountryViewModelGroup
  2. {
  3. public CountryViewModelGroup()
  4. {
  5. var NorthAmericaGroup = new SelectListGroup { Name = "North America" };
  6. var EuropeGroup = new SelectListGroup { Name = "Europe" };
  7. Countries = new List<SelectListItem>
  8. {
  9. new SelectListItem
  10. {
  11. Value = "MEX",
  12. Text = "Mexico",
  13. Group = NorthAmericaGroup
  14. },
  15. new SelectListItem
  16. {
  17. Value = "CAN",
  18. Text = "Canada",
  19. Group = NorthAmericaGroup
  20. },
  21. new SelectListItem
  22. {
  23. Value = "US",
  24. Text = "USA",
  25. Group = NorthAmericaGroup
  26. },
  27. new SelectListItem
  28. {
  29. Value = "FR",
  30. Text = "France",
  31. Group = EuropeGroup
  32. },
  33. new SelectListItem
  34. {
  35. Value = "ES",
  36. Text = "Spain",
  37. Group = EuropeGroup
  38. },
  39. new SelectListItem
  40. {
  41. Value = "DE",
  42. Text = "Germany",
  43. Group = EuropeGroup
  44. }
  45. };
  46. }
  47. public string Country { get; set; }
  48. public List<SelectListItem> Countries { get; }

两个组如下所示:

选项组示例

生成的 HTML:

  1. <form method="post" action="/Home/IndexGroup">
  2. <select id="Country" name="Country">
  3. <optgroup label="North America">
  4. <option value="MEX">Mexico</option>
  5. <option value="CAN">Canada</option>
  6. <option value="US">USA</option>
  7. </optgroup>
  8. <optgroup label="Europe">
  9. <option value="FR">France</option>
  10. <option value="ES">Spain</option>
  11. <option value="DE">Germany</option>
  12. </optgroup>
  13. </select>
  14. <br /><button type="submit">Register</button>
  15. <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
  16. </form>

多重选择Multiple select

如果 属性中指定的属性为 ,选择标记帮助程序会自动生成 asp-formultiple = "multiple"IEnumerable 属性。例如,如果给定以下模型:

using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;

namespace FormsTagHelper.ViewModels
{
    public class CountryViewModelIEnumerable
    {
        public IEnumerable<string> CountryCodes { get; set; }

        public List<SelectListItem> Countries { get; } = new List<SelectListItem>
        {
            new SelectListItem { Value = "MX", Text = "Mexico" },
            new SelectListItem { Value = "CA", Text = "Canada" },
            new SelectListItem { Value = "US", Text = "USA"    },
            new SelectListItem { Value = "FR", Text = "France" },
            new SelectListItem { Value = "ES", Text = "Spain"  },
            new SelectListItem { Value = "DE", Text = "Germany"}
         };
    }
}

及以下视图:

@model CountryViewModelIEnumerable

<form asp-controller="Home" asp-action="IndexMultiSelect" method="post">
    <select asp-for="CountryCodes" asp-items="Model.Countries"></select> 
    <br /><button type="submit">Register</button>
</form>

生成以下 HTML:

<form method="post" action="/Home/IndexMultiSelect">
    <select id="CountryCodes"
    multiple="multiple"
    name="CountryCodes"><option value="MX">Mexico</option>
<option value="CA">Canada</option>
<option value="US">USA</option>
<option value="FR">France</option>
<option value="ES">Spain</option>
<option value="DE">Germany</option>
</select>
    <br /><button type="submit">Register</button>
  <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>

无选择No selection

如果发现自己在多个页面中使用“未指定”选项,可创建模板用于消除重复的 HTML:

@model CountryViewModel

<form asp-controller="Home" asp-action="IndexEmpty" method="post">
    @Html.EditorForModel()
    <br /><button type="submit">Register</button>
</form>

Views/Shared/EditorTemplates/CountryViewModel.cshtml 模板:

@model CountryViewModel

<select asp-for="Country" asp-items="Model.Countries">
    <option value="">--none--</option>
</select>

添加 HTML <option> 元素并不局限于无选定内容用例。例如,以下视图和操作方法会生成与上述代码类似的 HTML:

public IActionResult IndexNone()
{
    var model = new CountryViewModel();
    model.Insert(0, new SelectListItem("<none>", ""));
    return View(model);
}
@model CountryViewModel

<form asp-controller="Home" asp-action="IndexEmpty" method="post">
    <select asp-for="Country">
        <option value="">&lt;none&gt;</option>
        <option value="MX">Mexico</option>
        <option value="CA">Canada</option>
        <option value="US">USA</option>
    </select> 
    <br /><button type="submit">Register</button>
</form>

根据当前的 <option> 值选择正确的 selected="selected" 元素(包含 Country 属性)。

public IActionResult IndexOption(int id)
{
    var model = new CountryViewModel();
    model.Country = "CA";
    return View(model);
}
 <form method="post" action="/Home/IndexEmpty">
      <select id="Country" name="Country">
          <option value="">&lt;none&gt;</option>
          <option value="MX">Mexico</option>
          <option value="CA" selected="selected">Canada</option>
          <option value="US">USA</option>
      </select>
      <br /><button type="submit">Register</button>
   <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
 </form>

其他资源Additional resources