ASP.NET Core 表單中的標籤協助程式

作者:Rick AndersonN. Taylor MullenDave PaquetteJerrie Pelser

本文件示範使用表單和常用在表單上的 HTML 項目。 HTML 表單項目提供用來將資料張貼回伺服器的主要機制 Web 應用程式。 本文件的大部分在描述標籤協助程式,以及它們如何協助您有效率地建立強大的 HTML 表單。 我們建議您先閱讀標籤協助程式簡介,然後才閱讀這份文件。

在許多情況下,HTML 助手提供了特定標籤助手的替代方式。 不過,重要的是要認識到標籤輔助器並不能取代 HTML 輔助工具,也沒有每個 HTML 輔助工具都有標籤輔助工具。 有 HTML 協助程式替代存在時,便會予以提及。

表單標籤輔助工具

表單標籤協助程式:

  • 產生 MVC 控制器動作或命名路由的 HTML <FORM>action 屬性值。

  • 產生隱藏 的請求驗證令牌 ,以防止跨站請求偽造(當與 HTTP Post 動作方法中的屬性一起使用 [ValidateAntiForgeryToken] 時)。

  • 提供 asp-route-<Parameter Name> 屬性,其中 <Parameter Name> 新增至路由值。 routeValuesHtml.BeginFormHtml.BeginRouteForm 參數提供類似的功能。

  • 有 HTML 輔助工具的替代方案 Html.BeginForm ,且 Html.BeginRouteForm

範例:

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

先前的表單標籤助手會產生以下 HTML:

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

MVC 執行階段會從表單標籤協助程式屬性 actionasp-controller 產生 asp-action 屬性值。 表單標籤協助程式也會產生隱藏的要求驗證權杖,以防止跨站台要求偽造 (搭配 HTTP Post 動作方法中的 [ValidateAntiForgeryToken] 屬性使用時)。 保護純 HTML 表單免於跨站請求偽造很困難,但表單標籤助手為你提供了這項服務。

使用具名路由

asp-route 標籤協助程式屬性也可以產生 HTML action 屬性的標記。 具有名為路由的應用程式,或會對註冊頁面使用下列標記:

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

Views/Account 資料夾中的許多檢視(當您使用個別帳戶建立新的 Web 應用程式時產生)包含 asp-route-returnurl 屬性:

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

注意

內建模板,returnUrl 只有在您嘗試存取受授權的資源但尚未通過身份驗證或授權時才會自動填充。 當您嘗試未經授權的存取時,安全性中介軟體會設定 returnUrl 並將您重新導向到登入頁面。

表單動作標記協助程式

表單動作標記協助程式會在產生的 formaction<button ...> 標記上產生 <input type="image" ...> 屬性。 formaction 屬性可讓您控制表單提交其資料的位置。 它會繫結至類型為<input>的元素和類型為<button>的元素。 表單動作標記協助程式允許使用多個 AnchorTagHelperasp- 屬性來控制會為相應元素產生哪個 formaction 連結。

支援 AnchorTagHelper 屬性來控制 formaction 的值:

屬性 描述
asp-controller 控制器的名稱。
asp-action 動作方法的名稱。
asp-area 區域的名稱。
asp-page Razor 頁面的名稱。
asp-page-handler Razor 頁處理常式的名稱。
asp-route 路徑的名稱。
asp-route-{value} 單一 URL 路由值。 例如: asp-route-id="1234"
asp-all-route-data 所有路由值。
asp-fragment URL 片段。

控制器範例提交

以下標記會在選擇輸入或按鈕時,將表單提交至 IndexHomeController 動作:

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

上述標記會產生下列 HTML:

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

提交至頁面範例

下列標記會將表單提交至 AboutRazor 頁面:

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

上述標記會產生下列 HTML:

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

提交至路由範例

請考量 /Home/Test 端點:

public class HomeController : Controller
{
    [Route("/Home/Test", Name = "Custom")]
    public string Test()
    {
        return "This is the test page";
    }
}

下列標記會將表單提交到 /Home/Test 端點。

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

上述標記會產生下列 HTML:

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

輸入標籤協助程式

輸入標籤協助器會將 HTML <輸入> 元素綁定到 Razor 檢視中的模型表達式。

語法:

<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 Helper 功能存在重疊。 如需詳細資訊,請參閱輸入標籤協助器的 HTML 協助程式替代方案一節。

  • 提供強類型。 如果屬性名稱更改且你沒有更新標籤輔助器,你會收到類似以下錯誤的錯誤:

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

Input 標籤協助程式會根據 .NET 型別設定 HTML type 屬性。 下表列出一些常見的 .NET 型別和產生的 HTML 型別 (不是每個 .NET 類型都列出)。

.NET 類型 輸入類型
布爾 type=“checkbox”
繩子 type=“text”
日期時間 type=“datetime-local”
位元 type=“number”
int type=“number”
Single、Double type=“number”

下表顯示輸入標籤協助程式將對應至特定的輸入類型的一些常見資料註解屬性 (不是每個驗證屬性都列出):

屬性 輸入類型
[電子郵件地址] type=“email”
[URL] type=“url”
[HiddenInput] type=“hidden”
[電話] type=“tel”
[DataType(DataType.Password)] type=“password”
[DataType(DataType.Date)] type=“date”
[DataType(DataType.Time)] type=“time”

範例:

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public class RegisterViewModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email Address")]
        public string Email { get; set; }

        [Required]
        [DataType(DataType.Password)]
        public string Password { get; set; }
    }
}
@model RegisterViewModel

<form asp-controller="Demo" asp-action="RegisterInput" method="post">
    <label>Email: <input asp-for="Email" /></label> <br />
    <label>Password: <input asp-for="Password" /></label><br />
    <button type="submit">Register</button>
</form>

上述程式碼會產生下列 HTML:

<form method="post" action="/Demo/RegisterInput">
    Email:
    <input type="email" data-val="true"
            data-val-email="The Email Address field is not a valid email address."
            data-val-required="The Email Address field is required."
            id="Email" name="Email" value=""><br>
    Password:
    <input type="password" data-val="true"
            data-val-required="The Password field is required."
            id="Password" name="Password"><br>
    <button type="submit">Register</button>
    <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>

套用至 EmailPassword 屬性的資料註解會產生模型的中繼資料。 輸入標籤協助程式會取用模型中繼資料,並產生 HTML5data-val-* 屬性 (請參閱模型驗證)。 這些屬性描述要附加至輸入欄位的驗證程式。 這提供低調的 HTML5 和 jQuery 驗證。 非干擾屬性的格式 data-val-rule="Error Message"為 ,其中 rule 是驗證規則的名稱(例如 data-val-required、 、 data-val-emaildata-val-maxlength等)。 如果屬性中提供了錯誤訊息,該錯誤訊息會以該 data-val-rule 屬性的值顯示。 另外還有 data-val-ruleName-argumentName="argumentValue" 格式的屬性,提供規則的其他詳細資料,例如 data-val-maxlength-max="1024"

將多個 input 控制項繫結至相同的屬性時,產生的控制項會共用相同的 id,這會使產生的標記無效。 若要防止重複,請明確指定每個控制項的 id 屬性。

核取方塊隱藏輸入欄位呈現

HTML5 中的核取方塊在未核取時不會提交值。 若要傳送未核取的核取方塊的預設值,Input Tag Helper 會為核取方塊產生額外的隱藏欄位。

例如,請考慮以下 Razor 標記,該標記使用輸入標籤協助程式來處理布林值模型屬性 IsChecked

<form method="post">
    <input asp-for="@Model.IsChecked" />
    <button type="submit">Submit</button>
</form>

上述 Razor 標記會產生類似下列的 HTML 標記:

<form method="post">
    <input name="IsChecked" type="checkbox" value="true" />
    <button type="submit">Submit</button>

    <input name="IsChecked" type="hidden" value="false" /> 
</form>

上述 HTML 標籤會顯示額外的隱藏輸入,其名稱為 IsChecked,且值為 false。 根據預設,這個隱藏的輸入會在表單結尾轉譯。 提交表單時:

  • 如果已勾選 IsChecked 核取方塊,則 truefalse 都會作為值提交。
  • 如果 IsChecked 核取方塊未被勾選,則只會提交隱藏的輸入值 false

ASP.NET Core 模型繫結程序在繫結到 bool 值時僅讀取第一個值,這會導致核取的核取方塊為 true,未核取的核取方塊為 false

若要設定隱藏輸入轉譯的行為,請在 CheckBoxHiddenInputRenderMode 上設定 MvcViewOptions.HtmlHelperOptions 屬性。 例如:

services.Configure<MvcViewOptions>(options =>
    options.HtmlHelperOptions.CheckBoxHiddenInputRenderMode =
        CheckBoxHiddenInputRenderMode.None);

上述程式碼會將 CheckBoxHiddenInputRenderMode 設定為 CheckBoxHiddenInputRenderMode.None,以停用核取方塊的隱藏輸入轉譯。 如需所有可用的轉譯模式,請參閱 CheckBoxHiddenInputRenderMode 列舉。

HTML 輔助元件作為輸入標籤輔助元件的替代方案

Html.TextBoxHtml.TextBoxForHtml.Editor、 與 Html.EditorFor 有與輸入標籤輔助器重疊的功能。 輸入標籤協助程式將會自動設定 type 屬性;而 Html.TextBoxHtml.TextBoxFor 不會。 Html.EditorHtml.EditorFor 管理集合、複雜物件與範本,而輸入標籤助理則不處理。 輸入標籤助手、Html.EditorForHtml.TextBoxFor 是強型別(使用 lambda 表達式),而 Html.TextBoxHtml.Editor 則不是(使用表達式名稱)。

HTML屬性

@Html.Editor()@Html.EditorFor() 執行它們的預設範本時,使用特殊的 ViewDataDictionary 項目,名為 htmlAttributes。 此行為會選擇性地使用 additionalViewData 參數來增強。 索引鍵 "htmlAttributes" 不區分大小寫。 索引鍵 "htmlAttributes" 的處理方式類似於傳遞給輸入協助程式 (例如 htmlAttributes)的 @Html.TextBox() 物件。

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

表達式名稱

asp-for 屬性值是 ModelExpression,並用作 Lambda 運算式的右邊。 因此,asp-for="Property1"在生成的程式碼中變成m => m.Property1,這也是為什麼不需要以Model作為前綴。 您可以使用 "@" 字元來開始內嵌運算式,並移至 m. 前:

@{
  var joe = "Joe";
}

<input asp-for="@joe">

產生下列內容:

<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 的結果。

您也可以使用檢視模型的屬性路徑巡覽至子屬性。 請考慮更複雜的模型類別,其中包含子系 Address 屬性。

public class AddressViewModel
{
    public string AddressLine1 { get; set; }
}
public class RegisterAddressViewModel
{
    public string Email { get; set; }

    [DataType(DataType.Password)]
    public string Password { get; set; }

    public AddressViewModel Address { get; set; }
}

在視圖中,我們繫結至 Address.AddressLine1

@model RegisterAddressViewModel

<form asp-controller="Demo" asp-action="RegisterAddress" method="post">
    <label>Email: <input asp-for="Email" /></label> <br />
    <label>Password: <input asp-for="Password" /></label><br />
    <label>Address: <input asp-for="Address.AddressLine1" /></label><br />
    <button type="submit">Register</button>
</form>

會為 Address.AddressLine1 產生下列 HTML:

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

運算式名稱和集合

範例,包含 Colors 陣列的模型:

public class Person
{
    public List<string> Colors { get; set; }

    public int Age { get; set; }
}

動作方法:

public IActionResult Edit(int id, int colorIndex)
{
    ViewData["Index"] = colorIndex;
    return View(GetPerson(id));
}

下列 Razor 示範如何存取特定 Color 元素:

@model Person
@{
    var index = (int)ViewData["index"];
}

<form asp-controller="ToDo" asp-action="Edit" method="post">
    @Html.EditorFor(m => m.Colors[index])
    <label asp-for="Age"></label>
    <input asp-for="Age" /><br />
    <button type="submit">Post</button>
</form>

Views/Shared/EditorTemplates/String.cshtml 範本:

@model string

<label asp-for="@Model"></label>
<input asp-for="@Model" /> <br />

使用 List<T> 的範例:

public class ToDoItem
{
    public string Name { get; set; }

    public bool IsDone { get; set; }
}

下列 Razor 示範如何逐一迭代集合:

@model List<ToDoItem>

<form asp-controller="ToDo" asp-action="Edit" method="post">
    <table>
        <tr> <th>Name</th> <th>Is Done</th> </tr>

        @for (int i = 0; i < Model.Count; i++)
        {
            <tr>
                @Html.EditorFor(model => model[i])
            </tr>
        }

    </table>
    <button type="submit">Save</button>
</form>

Views/Shared/EditorTemplates/ToDoItem.cshtml 範本:

@model ToDoItem

<td>
    <label asp-for="@Model.Name"></label>
    @Html.DisplayFor(model => model.Name)
</td>
<td>
    <input asp-for="@Model.IsDone" />
</td>

@*
    This template replaces the following Razor which evaluates the indexer three times.
    <td>
         <label asp-for="@Model[i].Name"></label>
         @Html.DisplayFor(model => model[i].Name)
     </td>
     <td>
         <input asp-for="@Model[i].IsDone" />
     </td>
*@

當值將在 asp-forHtml.DisplayFor 的相當情境中使用時,應該使用 foreach(如果可能的話)。 一般而言,forforeach 好 (若案例允許的話),因為它不需要配置列舉程式;不過,評估 LINQ 運算式中的索引子可能成本高昂且應該儘可能避免。

 

注意

上述加上註解的範例程式碼示範如何將 Lambda 運算式取代為 @ 運算子,來存取清單中的每個 ToDoItem

Textarea 標籤協助程式

Textarea Tag Helper 標籤協助程式類似於輸入標籤協助程式。

  • 針對 <textarea> 元素,生成 idname 屬性,以及來自模型的資料驗證屬性。

  • 提供強類型。

  • HTML 輔助工具替代:Html.TextAreaFor

範例:

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public class DescriptionViewModel
    {
        [MinLength(5)]
        [MaxLength(1024)]
        public string Description { get; set; }
    }
}
@model DescriptionViewModel

<form asp-controller="Demo" asp-action="RegisterTextArea" method="post">
    <textarea asp-for="Description"></textarea>
    <button type="submit">Test</button>
</form>

會產生下列 HTML:

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

標籤標籤協助器

  • <label>元素的表達式名稱上產生標籤標題與for屬性。

  • HTML 輔助工具替代:Html.LabelFor

Label Tag Helper 相較於純粹的 HTML 標籤元素,提供下列優點:

  • 您會自動從 Display 屬性取得描述性的標籤值。 預定的顯示名稱可能會隨著時間而改變,Display 屬性和標籤輔助工具的組合會在每個使用的地方都套用 Display

  • 原始碼的標記也比較少。

  • 強型別結合模型屬性。

範例:

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public class SimpleViewModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email Address")]
        public string Email { get; set; }
    }
}

@model SimpleViewModel

<form asp-controller="Demo" asp-action="RegisterLabel" method="post">
    <label asp-for="Email"></label>
    <input asp-for="Email" /> <br />
</form>

會為 <label> 項目產生下列 HTML:

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

標籤標籤協助程式產生了 "Email" 的 for 屬性值,這是與 <input> 項目建立關聯的識別碼。 標籤協助程式會產生一致的 idfor 項目,所以能夠正確地相關聯。 在此範例中的標題來自 Display 屬性。 如果模型未包含 Display 屬性,標題會是運算式的屬性名稱。 若要覆寫預設標題,請在標籤標記內新增標題。

驗證標籤協助程式

有兩個驗證標籤協助程式。 Validation Message Tag Helper (這會顯示模型上單一屬性的驗證訊息),和 Validation Summary Tag Helper (這會顯示驗證錯誤的摘要)。 Input Tag Helper 會根據您模型類別上的資料註釋屬性,將 HTML5 用戶端端驗證屬性新增至輸入項目。 也會在伺服器上執行驗證。 驗證標籤協助程式會在發生驗證錯誤時顯示這些錯誤訊息。

驗證訊息標籤協助程式

  • 新增 HTML5data-valmsg-for="property" 屬性至 span 元素,它會將驗證錯誤訊息附加在指定模型屬性的輸入欄位。 發生用戶端驗證錯誤時,jQuery 會在 <span> 項目顯示錯誤訊息。

  • 也會在伺服器上發生驗證。 客戶端可能關閉了 JavaScript,且部分驗證只能在伺服器端完成。

  • HTML 輔助工具替代:Html.ValidationMessageFor

Validation Message Tag Helper 與 HTML asp-validation-for 元素上的 屬性搭配使用。

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

驗證訊息標籤協助程式將會產生下列 HTML:

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

在相同屬性的 Validation Message Tag Helper 標籤協助程式之後,您通常會使用 Input。 這麼做會在造成錯誤的輸入附近顯示任何驗證錯誤訊息。

注意

您必須擁有包含正確 JavaScript 和 jQuery 指令碼引用的視圖,以進行客戶端驗證。 欲了解更多資訊,請參閱 模型驗證

發生伺服器端驗證錯誤時 (例如當您有自訂伺服器端驗證或是已停用用戶端驗證時),MVC 會將該錯誤訊息放置為 <span> 項目的主體。

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

驗證摘要標籤協助程式

  • 鎖定具有asp-validation-summary屬性的<div>元素。

  • HTML 輔助工具替代:@Html.ValidationSummary

Validation Summary Tag Helper 可用來顯示驗證訊息的摘要。 asp-validation-summary 屬性值可以是下列任一項:

asp-validation-summary(驗證摘要) 顯示的驗證訊息
All 屬性和模型層級
ModelOnly 型號
None

範例

在下列範例中,資料模型具有 DataAnnotation 屬性,這會在 <input> 元素上產生驗證錯誤訊息。 在發生驗證錯誤時,驗證標籤協助程式會顯示錯誤訊息:

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public class RegisterViewModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email Address")]
        public string Email { get; set; }

        [Required]
        [DataType(DataType.Password)]
        public string Password { get; set; }
    }
}
@model RegisterViewModel

<form asp-controller="Demo" asp-action="RegisterValidation" method="post">
    <div asp-validation-summary="ModelOnly"></div>
    <label>Email: <input asp-for="Email" /></label> <br />
    <span asp-validation-for="Email"></span><br />
    <label>Password: <input asp-for="Password" /></label><br />
    <span asp-validation-for="Password"></span><br />
    <button type="submit">Register</button>
</form>

產生的 HTML (當模型有效時):

<form action="/DemoReg/Register" method="post">
  <label>Email: <input name="Email" id="Email" type="email" value=""
   data-val-required="The Email field is required."
   data-val-email="The Email field is not a valid email address."
   data-val="true"></label><br>
  <span class="field-validation-valid" data-valmsg-replace="true"
   data-valmsg-for="Email"></span><br>
  <label>Password: <input name="Password" id="Password" type="password"
   data-val-required="The Password field is required." data-val="true"></label><br>
  <span class="field-validation-valid" data-valmsg-replace="true"
   data-valmsg-for="Password"></span><br>
  <button type="submit">Register</button>
  <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>

選擇標籤協助器

  • 為模型的屬性產生 select 以及相關聯的 option 項目。

  • 有 HTML 輔助工具的替代方案 Html.DropDownListFor ,且 Html.ListBoxFor

Select Tag Helper asp-for 指定 select 元素的模型屬性名稱,而 asp-items 指定 option 元素。 例如:

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

範例:

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

namespace FormsTagHelper.ViewModels
{
    public class CountryViewModel
    {
        public string Country { 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" },
        };
    }
}

Index 方法會初始化 CountryViewModel,設定所選國家,並將其傳遞給 Index 視圖。

public IActionResult Index()
{
    var model = new CountryViewModel();
    model.Country = "CA";
    return View(model);
}

HTTP POST Index 方法會顯示選取項目:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index(CountryViewModel model)
{
    if (ModelState.IsValid)
    {
        var msg = model.Country + " selected";
        return RedirectToAction("IndexSuccess", new { message = msg });
    }

    // If we got this far, something failed; redisplay form.
    return View(model);
}

Index 檢視:

@model CountryViewModel

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

它會產生下列 HTML (並選取 "CA"):

<form method="post" action="/">
     <select id="Country" name="Country">
       <option value="MX">Mexico</option>
       <option selected="selected" value="CA">Canada</option>
       <option value="US">USA</option>
     </select>
       <br /><button type="submit">Register</button>
     <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
   </form>

注意

我們不建議使用 ViewBagViewData 搭配選取標籤協助程式。 檢視模型在提供 MVC 元資料方面更穩健,且問題較少。

asp-for屬性值是特殊情況,不需要前Model綴。 其他標籤輔助屬性會執行(例如 asp-items)。

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

列舉綁定

使用 <select> 搭配 enum 屬性,並從 SelectListItem 值產生 enum 項目通常很方便。

範例:

public class CountryEnumViewModel
{
    public CountryEnum EnumCountry { get; set; }
}
using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public enum CountryEnum
    {
        [Display(Name = "United Mexican States")]
        Mexico,
        [Display(Name = "United States of America")]
        USA,
        Canada,
        France,
        Germany,
        Spain
    }
}

方法 GetEnumSelectList 會為一個列舉生成SelectList 物件。

@model CountryEnumViewModel

<form asp-controller="Home" asp-action="IndexEnum" method="post">
    <select asp-for="EnumCountry" 
            asp-items="Html.GetEnumSelectList<CountryEnum>()">
    </select> 
    <br /><button type="submit">Register</button>
</form>

您可以使用 Display 屬性來標記列舉程式清單,以取得更豐富的 UI:

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public enum CountryEnum
    {
        [Display(Name = "United Mexican States")]
        Mexico,
        [Display(Name = "United States of America")]
        USA,
        Canada,
        France,
        Germany,
        Spain
    }
}

會產生下列 HTML:

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

選項群組

當檢視模型包含一或多個SelectListGroup物件時,會產生 HTML <optgroup> 元素。

CountryViewModelGroupSelectListItem 項目分組成「北美洲」和「歐洲」群組:

public class CountryViewModelGroup
{
    public CountryViewModelGroup()
    {
        var NorthAmericaGroup = new SelectListGroup { Name = "North America" };
        var EuropeGroup = new SelectListGroup { Name = "Europe" };

        Countries = new List<SelectListItem>
        {
            new SelectListItem
            {
                Value = "MEX",
                Text = "Mexico",
                Group = NorthAmericaGroup
            },
            new SelectListItem
            {
                Value = "CAN",
                Text = "Canada",
                Group = NorthAmericaGroup
            },
            new SelectListItem
            {
                Value = "US",
                Text = "USA",
                Group = NorthAmericaGroup
            },
            new SelectListItem
            {
                Value = "FR",
                Text = "France",
                Group = EuropeGroup
            },
            new SelectListItem
            {
                Value = "ES",
                Text = "Spain",
                Group = EuropeGroup
            },
            new SelectListItem
            {
                Value = "DE",
                Text = "Germany",
                Group = EuropeGroup
            }
      };
    }

    public string Country { get; set; }

    public List<SelectListItem> Countries { get; }

這兩組如下所示:

選項群組範例

產生的 HTML:

 <form method="post" action="/Home/IndexGroup">
      <select id="Country" name="Country">
          <optgroup label="North America">
              <option value="MEX">Mexico</option>
              <option value="CAN">Canada</option>
              <option value="US">USA</option>
          </optgroup>
          <optgroup label="Europe">
              <option value="FR">France</option>
              <option value="ES">Spain</option>
              <option value="DE">Germany</option>
          </optgroup>
      </select>
      <br /><button type="submit">Register</button>
      <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
 </form>

多重選擇

選取標籤協助程式會自動產生 multiple = "multiple" 屬性,如果 asp-for 屬性中指定的屬性是 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>

沒有選取項目

如果您發現自己在多個頁面中使用「未指定」的選項,您可以建立範本,以避免重複 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.Countries.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>

其他資源