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> 新增至路由值。 Html.BeginFormHtml.BeginRouteFormrouteValues 參數提供類似的功能。

  • 有 HTML 協助程式的替代 Html.BeginFormHtml.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 執行階段會從表單標籤協助程式屬性 asp-controllerasp-action 產生 action 屬性值。 表單標籤協助程式也會產生隱藏的要求驗證權杖,以防止跨站台要求偽造 (搭配 HTTP Post 動作方法中的 [ValidateAntiForgeryToken] 屬性使用時)。 保護純粹的 HTML 表單抵禦跨站台要求偽造很困難,而表單標籤協助程式為您提供此服務。

使用具名路由

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

<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

表單動作標記協助程式

表單動作標記協助程式會在產生的 <button ...><input type="image" ...> 標記上產生 formaction 屬性。 formaction 屬性可讓您控制表單提交其資料的位置。 它會繫結至類型 image<輸入>元素和<按鈕>元素。 表單動作標記協助程式允許使用多個 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 片段。

提交至控制器範例

輸入或選取按鈕時,下列標記會將表單提交到 HomeControllerIndex 動作:

<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>">

輸入標籤協助程式:

  • 會為 asp-for 屬性中指定的運算式名稱產生 idname HTML 屬性。 asp-for="Property1.Property2" 等於 m => m.Property1.Property2。 運算式的名稱用於 asp-for 屬性值。 請參閱運算式名稱一節以取得其他資訊。

  • 根據套用至模型屬性的模型類型和資料註解屬性,設定 HTML type 屬性值

  • 已指定 HTML type 屬性值時不會予以覆寫

  • 從套用至模型屬性的資料註解屬性產生 HTML5 驗證屬性

  • Html.TextBoxForHtml.EditorFor 具有 HTML 協助程式功能重疊。 如需詳細資訊,請參閱輸入標籤協助程式的 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 類型 輸入類型
Bool type="checkbox"
String type="text"
Datetime type="datetime-local"
Byte type="number"
int type="number"
Single、Double type="number"

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

屬性 輸入類型
[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"

範例:

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">
    Email:  <input asp-for="Email" /> <br />
    Password: <input asp-for="Password" /><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-requireddata-val-emaildata-val-maxlength 等。)如果屬性中提供錯誤訊息,就會顯示為 data-val-rule 屬性的值。 另外還有 data-val-ruleName-argumentName="argumentValue" 格式的屬性,提供規則的其他詳細資料,例如 data-val-maxlength-max="1024"

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

核取方塊隱藏輸入轉譯

HTML5 中的核取方塊在未核取時不會提交值。 若要為未核取的核取方塊啟用預設值傳送,輸入標籤協助程式會產生核取方塊的額外隱藏輸入。

例如,請考慮以下 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

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

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

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

輸入標籤協助程式的 HTML 標記替代

Html.TextBoxHtml.TextBoxForHtml.EditorHtml.EditorFor 具有與輸入標籤協助程式重疊的功能。 輸入標籤協助程式將會自動設定 type 屬性;而 Html.TextBoxHtml.TextBoxFor 不會。 Html.EditorHtml.EditorFor 會處理集合、複雜的物件和範本;而輸入標籤協助程式不會。 輸入標籤協助程式 Html.EditorForHtml.TextBoxFor 為強型別 (它們使用 Lambda 運算式);而 Html.TextBoxHtml.Editor 不是 (它們使用運算式名稱)。

HtmlAttributes

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

@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">

搭配集合屬性,當 i 的值為 23 時,asp-for="CollectionProperty[23].Member" 會產生與 asp-for="CollectionProperty[i].Member" 相同的名稱。

當 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">
    Email:  <input asp-for="Email" /> <br />
    Password: <input asp-for="Password" /><br />
    Address: <input asp-for="Address.AddressLine1" /><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>

標籤標籤協助程式

  • 在運算式名稱的<標籤>元素上產生標籤標題和 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 span 元素上的 asp-validation-for 屬性搭配使用。

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

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

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

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

注意

您必須具有正確 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 Model
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>
    Email:  <input asp-for="Email" /> <br />
    <span asp-validation-for="Email"></span><br />
    Password: <input asp-for="Password" /><br />
    <span asp-validation-for="Password"></span><br />
    <button type="submit">Register</button>
</form>

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

<form action="/DemoReg/Register" method="post">
  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"><br>
  <span class="field-validation-valid" data-valmsg-replace="true"
   data-valmsg-for="Email"></span><br>
  Password: <input name="Password" id="Password" type="password"
   data-val-required="The Password field is required." data-val="true"><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.DropDownListForHtml.ListBoxFor

Select Tag Helperasp-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 屬性,並從 enum 值產生 SelectListItem 項目通常很方便。

範例:

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

兩個群組如下所示:

option group example

產生的 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>

其他資源