2013年1月29日 星期二

HtmlHelper Class

若要在 MVC 應用程式中使用 HTML 控制項,除了直接建立 HTML 控制項之外, 也可以使用 System.Web.Mvc.Html 命名空間底下的擴充控制項,來協助建立 HTML 控制項。 該命名空間包括支援表單、輸入控制項、連結、部分檢視和驗證等的類別。

FormExtensions

FormExtensions 類別是來用產生 <Form> 標籤用的,它包含三個擴充方法,分別是:

@{Html.BeginForm("Edit", "Employees");}

    @Html.HiddenFor(model => model.EmployeeID)
    <div>
        FirstName:
        @Html.TextBox("FirstName")
        @Html.ValidationMessageFor(model => model.FirstName)
    </div>
    <div>
        LastName:@Html.TextBox("LastName")
        @Html.ValidationMessageFor(model => model.LastName)
    </div>
    <div>
        Title:@Html.TextBox("Title")
    </div>
    <div>
        BirthDate:@Html.TextBox("BirthDate")
    </div>
    <div>
        Age:@Html.TextBox("Age")
    </div>
    <input type="submit" value="Save" />

@{Html.EndForm();}

產生內容

<form action="/Employees/Edit" method="post">
<input id="EmployeeID" name="EmployeeID" type="hidden" value="10" />
<div>
    FirstName:
    <input id="FirstName" name="FirstName" type="text" value="vito2" />
    <span data-valmsg-for="FirstName" data-valmsg-replace="true"></span>
</div>
<div>
    LastName:
    <input id="LastName" name="LastName" type="text" value="vito2" />
    <span data-valmsg-for="LastName" data-valmsg-replace="true"></span>
</div>
...
<input type="submit" value="Save" />

以下是 BeginForm 的另一種用法,可讀性較高:

@using (Html.BeginForm("Edit", "Employees"))
{
    @Html.HiddenFor(model => model.EmployeeID)
    <div>
        @Html.LabelFor(model => model.FirstName)
        @Html.EditorFor(model => model.FirstName)
        @Html.ValidationMessageFor(model => model.FirstName)
    </div>
    <div>
        @Html.LabelFor(model => model.LastName)
        @Html.EditorFor(model => model.LastName)
        @Html.ValidationMessageFor(model => model.LastName)
    </div>  
    <div>
        @Html.LabelFor(model => model.Title)
        @Html.EditorFor(model => model.Title)
    </div> 
    <div>
        @Html.LabelFor(model => model.BirthDate)
        @Html.EditorFor(model => model.BirthDate)
    </div>     
    <div>
        @Html.LabelFor(model => model.Age)
        @Html.EditorFor(model => model.Age)
    </div>   
    <input type="submit" value="Save"/>
}

BeginForm 有多個多載方法,其中一個 BeginForm(actionName, controllerName, method) 可以用來設定表單提交時,要使用哪一種 action method 處理。

LabelExtensions 、 DisplayExtensions 、 DisplayTextExtensions

通常為了在 View 中顯示特定資料,我們會在 Controller 中,將資料先儲存在 ViewData 中,再由 View 中取出。如下面範例:

public ActionResult About()
{
    ViewData["Message"] = "歡迎使用 ASP.NET MVC!";
}
@ViewData["Message"].ToString() 

MVC 提供我們幾個更簡便的方式以顯示這些資料。 你可以透過 DisplayExtensions 類別提供的下列方法,將物件資料,以 HTML 格式呈現:

Display 方法通常用來顯示 ViewData 字典中的資料; DisplayForDisplayForModel 方法通常用來顯示 Model 屬性所公開之物件的値。

[DisplayName("員工")]
    public class Person
    {
        [DisplayName("編號")]
        public int ID { get; set; }

        [Required()]
        [DisplayName("大名")]
        public string FirstName { get; set; }

        [Required(ErrorMessage = "請輸入LastName")]
        [DisplayName("姓氏")]
        public string LastName { get; set; }

        [Required()]
        [MaxLength(10)]
        [DisplayName("電話")]
        public string Tel { get; set; }

        [DisplayName("已婚")]
        public bool Merried { get; set; }
    }

LabelExtensions

LabelExtensions 會使用 <label> 標籤來轉譯指定的 Property 的 name 。它包含底下幾個方法:

  • Label :使用字串指定 Property ,回傳該 Peoperty 的顯示名稱。
  • LabelFor :使用 Expression 指定 Property ,回傳該 Peoperty 的顯示名稱。
  • LabelForModel :這個方法,隱含地使用模型。回傳該 Model 的 Property 名稱,若不指定 Property 則回傳 Model 的顯示名稱。
@Html.Label("FirstName", new { @class = "test classA" }) <%--回傳 property 設定的 DisplayName--%>
@Html.LabelFor(m => m.FirstName, new { @class = "test classB" })
@Html.LabelForModel("FirstName")                      <%--回傳 property name--%>
@Html.LabelForModel("FirstName", new { @class = "test classA" })
@Html.LabelForModel(new { @class = "test classB" })   <%--若不指定 property , 會回傳 model name--%>
<label class="test classA" for="FirstName">大名</label>
<label class="test classB" for="FirstName">大名</label>
<label for="">FirstName</label> 
<label class="test classA" for="">FirstName</label>
<label class="test classA" for="">學生</label>

DisplayTextExtensions

DisplayTextExtensions 會直接將指定的 Property 的 value 轉譯出去。它包含底下幾個方法:

  • DisplayText (string name) :使用字串指定 Property
  • DisplayTextFor (Expression expression) :使用 Expression 指定 Property
<div>
            @Html.DisplayText("FirstName")
        </div>
        <div>
            @Html.DisplayTextFor(m => m.FirstName)
        </div>
<div>
            vito
        </div>
        <div>
            vito
        </div>

DisplayExtensions

DisplayExtensions 會直接將指定的 Property 的 value 轉譯出去,而且支援使用 template 來設定輸出的樣式。它包含底下幾個方法:

  • Display :使用指定的範本,傳回由字串指定的 Property 的 Value 。
  • DisplayFor :使用指定的範本,傳回由 Expression 指定的 Property 的 Value 。
  • DisplayForModel :使用指定的範本,傳回模型中每一個屬性的 Name 和 Value 。
@Html.Display("Tel", "myTelTemplate")
@Html.DisplayFor(m => m.Tel, "myTelTemplate")
@Html.DisplayForModel()
@Html.DisplayForModel("myEmployeeTemplate")
@model String
<span class="tel">@System.Text.RegularExpressions.Regex.Replace(Model, @"(\d{2})(\d{3})(\d{4})", "$1-$2-$3");</span>
@model Person
<div>@Model.FirstName</div>
<div>@Model.LastName</div>
<span class="tel">02-393-9889;</span>

<span class="tel">02-393-9889;</span>

<div class="display-label">編號</div>
<div class="display-field">3</div>
<div class="display-label">大名</div>
<div class="display-field">vito</div>
<div class="display-label">姓氏</div>
<div class="display-field">shao</div>
<div class="display-label">電話</div>
<div class="display-field">023939889</div>
<div class="display-label">已婚</div>
<div class="display-field"><input class="check-box" disabled="disabled" type="checkbox" /></div>

<div>vito</div>
<div>shao</div>
<div>023939889</div>

Display

使用指定的範本,傳回運算式表示的物件中每一個屬性的 HTML 標記。

public static MvcHtmlString Display(this HtmlHelper html, string expression);
public static MvcHtmlString Display(this HtmlHelper html, string expression, string templateName);
public static MvcHtmlString Display(this HtmlHelper html, string expression, string templateName, string htmlFieldName);

public static MvcHtmlString Display(this HtmlHelper html, string expression, object additionalViewData);
public static MvcHtmlString Display(this HtmlHelper html, string expression, string templateName, string htmlFieldName, object additionalViewData);

您可以使用 Display 方法顯示從 ViewData 字典和從 Model 屬性所公開之物件的資料。

@ViewData["Message"].ToString()  @* 一般顯示方法 *@

@Html.Display("Message")         @* 若有 Message 物件,則將其值顯示出來 *@

@Html.Label("FirstName"):       @* 顯示 Employees 公開的屬性 FirstName 的欄位名稱 *@
@Html.Display("FirstName")       @* 顯示 Employees 公開的屬性 FirstName 的值 *@
@Html.Label("BirthDate"):
@Html.Display("BirthDate", "myDateTime")    @* 使用 myDateTime 這個 Partail View ,顯示 BirthDate 物件值 *@

上面範例中的 myDateTime 是一個自訂的 partial view (user control) ,程式碼如下:

<span style="font-weight:bold;color:green;">
  @Html.Encode(string.Format("{0:yyyy\\/MM\\/dd}", Model))
</span>

DisplayFor

使用指定的範本,傳回由 Expression 表示之物件中包含各個屬性值的字串。

其用法同 Display ,只是它的運算式是一個強型別物件

public static MvcHtmlString DisplayFor(this HtmlHelper html, Expression expression);
public static MvcHtmlString DisplayFor(this HtmlHelper html, Expression expression, string templateName);
public static MvcHtmlString DisplayFor(this HtmlHelper html, Expression expression, string templateName, string htmlFieldName);

public static MvcHtmlString DisplayFor(this HtmlHelper html, Expression expression, object additionalViewData);
public static MvcHtmlString DisplayFor(this HtmlHelper html, Expression expression, string templateName, string htmlFieldName, object additionalViewData);
@Html.LabelFor(emp => emp.FirstName):
@Html.DisplayFor(emp => emp.FirstName)
@Html.LabelFor(emp => emp.BirthDate):
@Html.DisplayFor( emp => emp.BirthDate , "myDateTime")

DisplayForModel

使用指定的範本,傳回模型中每一個屬性的 HTML 標記

public static MvcHtmlString DisplayForModel(this HtmlHelper html);
public static MvcHtmlString DisplayForModel(this HtmlHelper html, object additionalViewData);
public static MvcHtmlString DisplayForModel(this HtmlHelper html, string templateName);
public static MvcHtmlString DisplayForModel(this HtmlHelper html, string templateName, object additionalViewData);
public static MvcHtmlString DisplayForModel(this HtmlHelper html, string templateName, string htmlFieldName);
public static MvcHtmlString DisplayForModel(this HtmlHelper html, string templateName, string htmlFieldName, object additionalViewData);

1. 通常在強型別的 Veiw 中,要顯示該型別中特定的公開資料,你可以如此做:

<div>FirstName:@Html.DisplayFor(emp => emp.FirstName)</div>
<div>LastName:@Html.DisplayFor(emp => emp.LastName)</div>
<div>BirthDate:@Html.DisplayFor(emp => emp.BirthDate)</div>

2. 若要顯示該型別的所有公開的資料,使用直接使用 DisplayForModel 轉譯整個模型,以下範例:

@Html.DisplayForModel()

它就會自動將該 Model 中的所有公開屬性,轉譯成 html 字串,如下所示:

<div class="display-label">員工ID</div>
<div class="display-field">2</div>
<div class="display-label">名</div>
<div class="display-field">Fuller</div>
<div class="display-label">姓</div>
<div class="display-field">Andrew</div>
<div class="display-label">Title</div>
<div class="display-field">Vice President, Sales</div>
<div class="display-label">TitleOfCourtesy</div>
...

3. 你也可以將該模型資料,交由指定的範本(partial view or user control)來產出。 也就是在 user control 中設計你要的樣式,再使用這個 user control 來展現你的模型資料。 如下範例:

@Html.DisplayForModel("EmpDetail")
  @model MvcApplication1.Models.Employees  <div>FirstName:@Html.DisplayFor(emp => emp.FirstName)</div>
<div>LastName:@Html.DisplayFor(emp => emp.LastName)</div>
<div>BirthDate:@Html.DisplayFor(emp => emp.BirthDate)</div>

InputExtensions

InputExtensions represents support for HTML input controls in an application. 這個類別包含了五個擴充方法,用來建立以下五種 html 中的 input 項目:

這五個擴充方法也都各有一個加了 For 結尾的擴充方法,如 TextBoxFor , CheckBoxFor , HiddenFor , PasswordFor , HiddenFor 用來接受一個運算式物件的參數。

下面這個例子,是他們在使用上的差別

@Html.TextBoxFor("Caption")
    @Html.TextBoxFor(model => model.Title)
<input id="title1" name="Caption" type="text" value="" />
    <input id="Title" name="Title" type="text" value="Aniseed Syrup" />

EditorExtensions

EditorExtensions 底下只有一個 @Html.Editor 方法,它可以產生像 @Html.TextBox 一樣的 input control 。 除此之外,最主要的差別在 @Html.TextBox 只會產生 type="text" 屬性的 input control ,而 @Html.Editor 則會自動根據 Model 的 Property 型別,自動使用適合的 type 來建立 input control 。 還有這個方法也可搭配 templates 產出指定的樣式。

public static MvcHtmlString Editor(string expression);
public static MvcHtmlString EditorFor<TModel, TValue>(Expression<Func<TModel, TValue>> expression, string templateName, string htmlFieldName, object additionalViewData);
public static MvcHtmlString EditorForModel(string templateName, string htmlFieldName, object additionalViewData);

@Html.TextBoxFor(m => m.Merried)    // Merried 是 boolean 型別
            @Html.EditorFor(m => m.Merried)     // Merried 是 boolean 型別
<input id="Merried" name="Merried" type="text" value="" />
            <input id="Merried" name="Merried" type="checkbox" value="true" />

LinkExtensions

LinkExtensions 類別主要用來產生 HTML 的連結控制項。

ActionLink

RouteLink

建立 Areas 的連結

若我們使用 Areas 功能,要注意的首先是控制器重複的問題。另一個常見需求就是如何建立 Admin 區域的連結,或者如何由 Admin 區域建立外層網頁的連結。

如何使用 ActionLink 或 RouteLink 建立 Admin 區域連結?

如何由 Admin 區域連結到外層的網頁?

@Html.ActionLink("ActionLink1", "List", "Employees", new { area = "" }, null) 
    @Html.ActionLink("ActionLink2", "List",  new { area = "", controller = "Employees" }, null) 
        
    @Html.RouteLink("RouteLink1", "DefaultA", new { controller = "Employees", action = "List" })
    @Html.RouteLink("RouteLink2", new { area = "", controller = "Employees", action = "List" })

ChildActionExtensions

ChildActionExtensions 類別主要用來呼叫子系的 action method ,以取得 partial view 內容。

public static MvcHtmlString Action(this HtmlHelper htmlHelper, string actionName);
public static MvcHtmlString Action(this HtmlHelper htmlHelper, string actionName, object routeValues);
public static MvcHtmlString Action(this HtmlHelper htmlHelper, string actionName, string controllerName);
public static MvcHtmlString Action(this HtmlHelper htmlHelper, string actionName, string controllerName, object routeValues);

public static void RenderAction(this HtmlHelper htmlHelper, string actionName);
public static void RenderAction(this HtmlHelper htmlHelper, string actionName, object routeValues);
public static void RenderAction(this HtmlHelper htmlHelper, string actionName, string controllerName);
public static void RenderAction(this HtmlHelper htmlHelper, string actionName, string controllerName, object routeValues);

Action

Action 方法會叫用指定的子系的 action method 已取得回應的 partial view,並以 HTML 字串形式傳回結果。

@model MvcApplication1.Models.Customers

@Html.Action("CustomerOrders", new { CustomerID = Model.CustomerID })  

叫用 controller 中的 CustomerOrders 方法,並傳入參數 CustomerID 。

public ActionResult CustomerOrders(string CustomerID)
{
    NorthwindEntities db = new NorthwindEntities();

    var query = from order in db.Orders
                where order.CustomerID == CustomerID
                select order;

    return View(query.ToList());
}
@model IEnumerable<MvcApplication1.Models.Orders>
<table>
@foreach (var item in Model)
{
    <tr>
        <td>@Html.DisplayFor(modelItem => item.CustomerID)</td>
        <td>@Html.DisplayFor(modelItem => item.OrderDate)</td>
        <td>@Html.DisplayFor(modelItem => item.ShipAddress)</td>
        <td>@Html.DisplayFor(modelItem => item.ShipCity)</td>
    </tr>
}
</table>

RenderAction

RenderActionAction 功能,差別在它不傳回值,直接將轉譯的 HTML 碼輸出到 parent view。

@{ Html.RenderAction("ShowTime", "Home"); }

叫用 Home Controller 中的 ShowTime 方法。

public ActionResult ShowTime()
{
    return View();
}
@DateTime.Now.ToString()

PartialExtensions and RenderPartialExtensions

PartialExtensionsRenderPartialExtensions 類別都是用來取得 partial view 內容。 和 ChildActionExtensions 差別在不會呼叫 controller 中的 action method 。

public static MvcHtmlString Partial(this HtmlHelper htmlHelper, string partialViewName);

public static void RenderPartial(this HtmlHelper htmlHelper, string partialViewName);

Partial

Partial 方法會將 partial view 轉譯成 HTML 編碼字串,然後回傳字串。

@Html.Partial("CopyRightControl")
<p>Copyright © 2013 XXX Inc. All rights reserved</p>

RenderPartial

RenderPartial 同 Partial 功能,差別在它不傳回值,直接將轉譯的 HTML 碼輸出到 parent view。

@{ Html.RenderPartial("CopyRightControl"); }

ValidationExtensions

ValidationExtensions 包含以下方法:

在上面幾個方法中, ValidateValidationMessage 主要差異在於 Validate 回傳的訊息是經過 Encode 的,也就是會先將 html 標籤轉成字碼。 而 ValidationMessage 不會,所以若訊息文字中含有 html 標籤,就會顯示出該有的樣式。 另外帶有 For 字尾的方法表示可以利用 expression 表示式來指定驗證欄位,也就是透過強型別方式來做設定;而不帶 For 結尾的方法就是只能使用字串方式來設定驗證欄位。

MVC 的 Model 驗證機制,讓我們可以只透過 Model 的 DataAnnotations 屬性設定,就可以提供用戶端和伺服器驗證檢查,而不需要撰寫其他程式碼。 這些驗證後所產生的錯誤訊息會自動存放在 ModelState 系統變數中, ModelState 是一個 ModelStateDictionary 型別物件,哪一個 Property Name 驗證有錯誤,就會建立一筆資料,並將錯誤存放在 Values.Errors 屬性,同時將原始資料保留在 Values.Value 屬性中。 你也可以在程式碼中透過 ModelState.AddModelError 方法,將自訂的錯誤訊息記錄下來,並依據自行定義的 key 值分類。

使用 ValidationMessageValidationMessageFor 時,必須指定一個 Property ,就會顯示與該 Property 相關的錯誤訊息,但只會顯示一筆。 而 ValidationSummary 則會顯示 ModelState 中的全部錯誤訊息。

[HttpPost]
public ActionResult Create(Student student)
{
    ModelState.AddModelError("keyA", "錯誤訊息A1");
    ModelState.AddModelError("keyB", "錯誤訊息B1");

    if (ModelState.IsValid)
    {
        db.Students.Add(student);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(student);
}
@Html.ValidationSummary("", new { @class = "text-danger" })

@Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" })
@Html.ValidationMessageFor(model => model.FirstMidName, "", new { @class = "text-danger" })
@Html.ValidationMessageFor(model => model.EnrollmentDate, "", new { @class = "text-danger" })

清除

如果你不想錯誤訊息輸出到 View 端,你可以叫用 ModelState.Clear 方法移除全部記錄,或者 ModelState.Remove 移除特定項目。

ModelState.Clear();
ModelState.Remove("LastName");

沒有留言:

張貼留言