ASP.NET MVC架構與實戰系列之三:MVC控件解析


     俗話說"工欲善其事,必先利其器",要真正的開發MVC網站,不光要掌握我在前兩節提到的理論知識,而且還要擁有強大的武器裝備。MVC視圖開發是通過HtmlHelper的各種擴展方法來實現的(位於System.Web.Mvc.Html下)。主要包含以下7大類:FormExtensions、InputExtensions、LinkExtensions、SelectExtensions、TextAreaExtensions、ValidationExtensions及RenderPartialExtensions類。不僅如此,通過HtmlHelper的擴展方法還能開發更多的自定義控件(如我以后講到的GridView等)。下面我一一講解這些控件。

FormExtensions:在視圖中添加表單和表單路由,分別是BeginForm、BeginRouteForm和EndForm。BeginForm用於定義表單的開始部分,重載方法如下:

BeginForm();
BeginForm(object routeValues);
BeginForm(RouteValueDictionary routeValues);
BeginForm(string actionName,string controllerName);
BeginForm(string actionName,string controllerName,object routeValues);
BeginForm(string actionName,string controllerName,RouteValueDictionary routeValues);
BeginForm(string actionName,string controllerName,FormMethod method);
BeginForm(string actionName,string controllerName,object routeValues,FormMethod method);
BeginForm(string actionName,string controllerName,RouteValueDictionary routeVaues,FormMethod method);
BeginForm(string actionName,string controllerName,FormMethod method,object htmlAttributes);
BeginForm(string actionName,string controllerName,FormMethod method,IDictionary<string,object> htmlAttributes);
BeginForm(string actionName,string controllerName,object routeValues,FormMethod method,object htmlAttributes);
BeginForm(string actionName,string controllerName,RouteValueDictionary routeValues,FormMethod method,IDictionary<string,object> htmlAttributes);

可以通過以下代碼設置路由對象:

Html.BeginForm(new { controller = "blog", action = "show", author = "miracle" })

對應生成的HTML代碼(默認提交方法為post):

<form action="/blog/show/miracle" method="post"/>

也可以通過BeginForm設置提交方法,以FormMethod為最高優先級,然后才是屬性設置。

Html.BeginForm("show", "blog", FormMethod.Post, new { method = "get" })

對應生成的HTML代碼(盡管后面又對方法進行了更改,但是以FormMethod優先級最高,提交方法仍然為post):

<form action="/blog/show" method="post"/>

還可以設置屬性(例如id,class等),如同時在屬性中設置了action,則以屬性設置為最高優先級。

Html.BeginForm("show", "blog",
                 new RouteValueDictionary { { "author", "miracle" } },
                 FormMethod.Post,
                 new RouteValueDictionary { { "action", "compose" }, { "class", "begin-form" } })

對應生成的HTML代碼(添加了class,同時更改了action):

<form action="/blog/show/miracle" class="begin-form" method="post"/>

同時,也可以利用BeginRouteForm來定義form開頭部分,不過不同的是,此時不用強制指定controller(當前也可以指定),默認當前頁面所在的目錄對應的控制器。重載方法如下:

BeginRouteForm(object routeValues);
BeginRouteForm(RouteValueDictionary routeValues);
BeginRouteForm(string routeName);
BeginRouteForm(string routeName,object routeValues);
BeginRouteForm(string routeName,RouteValueDictionary routeValues);
BeginRouteForm(string routeName,FormMethod method);
BeginRouteForm(string routeName,object routeValues,FormMethod method);
BeginRouteForm(string routeName,RouteValueDictionary routeValues,FormMethod method);
BeginRouteForm(string routeName,FormMethod method,object htmlAttributes);
BeginRouteForm(string routeName,FormMethod method,IDictionary<string,object> htmlAttributes);
BeginRouteForm(string routeName,object routeValues,FormMethod method,object htmlAttributes);
BeginRouteForm(string routeName,RouteValueDictionary routeValues,FormMethod method,IDictionary<string,object> htmlAttributes);

可以通過以下代碼設置路由對象:

Html.BeginRouteForm(new { action="show"})

對應生成的HTML代碼(盡管沒有指定controller):

<form action="/blog/show" method="post"/>

其他的設置與BeginForm類似。可通過EndForm定義結尾部分,不過一般在實際項目中,使用using來定義form而不是調用Html.EndForm。

<% using (Html.BeginForm(new { controller = "blog", action = "show", author = "miracle" }))
  {%>
  表單內容
<%} %>

InputExtensions:包含設置CheckBox、RadioButton、Hidden、TextBox及Password控件。

首先來看CheckBox控件,重載方法列表:

CheckBox(string name);
CheckBox(string name,bool isChecked);
CheckBox(string name,bool isChecked,object htmlAttributes);
CheckBox(string name,object htmlAttributes);
CheckBox(string name,IDictionary<string,object> htmlAttributes);
CheckBox(string name,bool isChecked,IDictionary<string,object> htmlAttributes);

我們來看看對應的頁面代碼:

<%using (Html.BeginForm("CheckBox", "Control"))
  {%>
<fieldset>
    <legend>設置字體</legend>
    <%=Html.CheckBox("chkBlack", true, new  { id="chkBlack"})%>
    <label for="chkBlack">
        黑色</label>
    <%=Html.CheckBox("chkBlue", false, new { id = "chkBlue" })%>
    <label for="chkBlue">
        藍色</label>
</fieldset>
<%} %>

對應生成的HTML代碼:

<form action="/Control/CheckBox" method="post">
    <fieldset>
        <legend>設置字體</legend>
        <input checked="checked" id="chkBlack" name="chkBlack" type="checkbox" value="true" />
        <input name="chkBlack" type="hidden" value="false" />
        <label for="chkBlack">
            黑色</label>
        <input id="chkBlue" name="chkBlue" type="checkbox" value="true" />
        <input name="chkBlue" type="hidden" value="false" />
        <label for="chkBlue">
            藍色</label>
    </fieldset>
</form>

我們可以看出,每一個CheckBox都會對應另外生成一個隱藏控件,可以利用它來檢測復選框的選中狀態。

public ActionResult ShowCheckBox(FormCollection form)
{
    bool isCheckedBlack = form["chkBlack"].Contains("true");
    bool isCheckedBlue = form["chkBlue"].Contains("true");
    ViewData["Black"] = isCheckedBlack;
    ViewData["Blue"] = isCheckedBlue;
    return View();
}

接下來看看單選控件RadioButton,重載方法列表:

RadioButton(string name,object value);
RadioButton(string name,object value,object htmlAttributes);
RadioButton(string name,object value,IDictionary<string,object> htmlAttributes);
RadioButton(string name,object value,bool isChecked);
RadioButton(string name,object value,bool isChecked,object htmlAttributes);
RadioButton(string name,object value,bool isChecked,IDictionary<string,object> htmlAttributes);
<%using (Html.BeginForm("RadioButton", "Control"))
  {%>
<fieldset>
    <legend>設置字體</legend>
    <%=Html.RadioButton("color", "black", true, new { id = "rbBlack" })%>
    <label for="rbBlack">
        黑色</label>
    <%=Html.RadioButton("color", "blue", false, new { id = "rbBlue" })%>
    <label for="rbBlue">
        藍色</label>
</fieldset>
<%} %>
<form action="/Control/RadioButton" method="post">
<fieldset>
    <legend>設置字體</legend>
    <input checked="checked" id="rbBlack" name="color" type="radio" value="black" />
    <label for="rbBlack">
        黑色</label>
    <input id="rbBlue" name="color" type="radio" value="blue" />
    <label for="rbBlue">
        藍色</label>
</fieldset>
</form>

我們可以發現RadioButton的name值是一樣的,保證單選的唯一性。同時不需要額外的隱藏控件來保存是否選中。
接下來看看隱藏控件是如何實現的:

Hidden(string name);
Hidden(string name,object value);
Hidden(string name,object value,object htmlAttributes);
Hidden(string name,object value,IDictionary<string,object> htmlAttributes);

生成的隱藏控件及HTML代碼如下:

Html.Hidden("name", "miracle");
<input id="name" name="name" type="hidden" value="miracle" />

由於文本框及密碼的生成方式與Hidden類似,這里就不再介紹了。

LinkExtensions:在視圖中設置鏈接,包含ActionLink和RouteLink。兩者基本功能一致,只是后者可以指定路由名稱而已。

我們以ActionLink為例來講解,重載方法列表:

ActionLink(string linkText,string actionName);
ActionLink(string linkText,string actionName,object routeValues);
ActionLink(string linkText,string actionName,object routeValues,object htmlAttributes);
ActionLink(string linkText,string actionName,RouteValueDictionary routeValues);
ActionLink(string linkText,string actionName,RouteValueDictionary routeValues,IDictionary<string,object> htmlAttributes);
ActionLink(string linkText,string actionName,string controller);
ActionLink(string linkText,string actionName,string controller,object routeValues,object htmlAttributes);
ActionLink(string linkText,string actionName,string controller,RouteValueDictionary routeValues,IDictionary<string,object> htmlAttributes);
ActionLink(string linkText,string actionName,string controller,string protocol,string hostName,string fragment,object routeValues,object htmlAttributes);
ActionLink(string linkText,string actionName,string controller,string protocol,string hostName,string fragment,RouteValueDictionary routeValues,IDictionary<string,object> htmlAttributes);
Html.ActionLink("Miracle's Blog", "Show", "Blog")
<a href="/Blog/Show">Miracle's Blog</a>

在這里,簡單的列舉一下RouteLink的相關方法:

RouteLink(string linkText,object routeValues);
RouteLink(string linkText,RouteValueDictionary routeValues);
RouteLink(string linkText,string routeName,object routeValues);
RouteLink(string linkText,string routeName,RouteValueDictionary routeValues);
RouteLink(string linkText,object routeValues,object htmlAttributes);
RouteLink(string linkText,RouteValueDictionary routeValues,IDictionary<string,object> htmlAttributes);
RouteLink(string linkText,string routeName,object routeValues,object htmlAttributes);
RouteLink(string linkText,string routeName,RouteValueDictionary routeValues,IDictionary<string,object> htmlAttributes);
RouteLink(string linkText,string routeName,string protocol,string hostName,string fragment,object routeValues,object htmlAttributes);
RouteLink(string linkText,string routeName,string protocol,string hostName,string fragment,RouteValueDictionary routeValues,IDictionary<string,object> htmlAttributes);
Html.RouteLink("Miracle's Blog", "default", new { author="miracle"})
<a href="/Blog/Show/miracle">Miracle's Blog</a>

SelectExtensions:包含DropDownList和ListBox控件。前者為下拉列表,后者為列表框。

DropDownList下拉列表的重載方法列表:

DropDownList(string name);
DropDownList(string name,string optionLabel);
DropDownList(string name,IEnumerable<SelectListItem> selectList,string optionLabel);
DropDownList(string name,IEnumerable<SelectListItem> selectList,string optionLabel,object htmlAttributes);
DropDownList(string name,IEnumerable<SelectListItem> selectList);
DropDownList(string name,IEnumerable<SelectListItem> selectList,object htmlAttributes);
DropDownList(string name,IEnumerable<SelectListItem> selectList,IDictionary<string,object> htmlAttributes);
DropDownList(string name,IEnumerable<SelectListItem> selectList,string optionLabel,IDictionary<string,object> htmlAttributes);

查看一下DropDownList應用頁面及HTML:

public ActionResult ShowDropDownList()
{
    ViewData["Category"] = new SelectList(db.Categories, "CategoryID", "CategoryName");
    return View();
}
<%using (Html.BeginForm("SelectDropDownList", "Control"))
  {%>
<fieldset>
    <legend>選擇類別</legend>
    <%=Html.DropDownList("Category")%>
    <input type="submit" value="選擇"/>
</fieldset>
<%} %>

<form action="/Control/SelectDropDownList" method="post">
<fieldset>
<legend>選擇產品類別</legend>
    <select id="Category" name="Category">
        <option value="1">Beverages</option>
        <option value="2">Condiments</option>
        <option value="3">Confections</option>
        <option value="4">Dairy Products</option>
        <option value="5">Grains/Cereals</option>
        <option value="6">Meat/Poultry</option>
        <option value="7">Produce</option>
        <option value="8">Seafood</option>
    </select>
 <input type="submit" value="選擇"/></fieldset>
</form>

要獲取當前選中的項,代碼如下:

public ActionResult SelectDropDownList(FormCollection form)
{
    var selectedCategories = form["Category"];
    ViewData["SelectCategory"] = new SelectList(db.Categories, "CategoryID", "CategoryName", selectedCategories);
    return View();
}
<%using (Html.BeginForm("ShowDropDownList", "Control"))
{%>
    <fieldset>
        <legend>當前選中類別</legend>
        <%=Html.DropDownList("SelectCategory")%>
        <input type="submit" value="返回"/>
    </fieldset>
<%} %>

<form action="/" method="post">
<fieldset>
    <legend>當前選中類別</legend>
    <select id="SelectCategory" name="SelectCategory">
        <option value="1">Beverages</option>
        <option value="2">Condiments</option>
        <option value="3">Confections</option>
        <option value="4">Dairy Products</option>
        <option value="5">Grains/Cereals</option>
        <option value="6">Meat/Poultry</option>
        <option value="7">Produce</option>
        <option selected="selected" value="8">Seafood</option>
    </select>
    <input type="submit" value="返回"/>
</fieldset>
</form>

ListBox列表框可選中多個項(設置multiple):

ListBox(string name);
ListBox(string name,IEnumerable<SelectListItem> selectList);
ListBox(string name,IEnumerable<SelectListItem> selectList,object htmlAttributes);
ListBox(string name,IEnumerable<SelectListItem> selectList,IDictionary<string,object> htmlAttributes);

查看一下ListBox應用頁面及HTML:

public ActionResult ShowListBox()
{
    ViewData["Category"] = new SelectList(db.Categories, "CategoryID", "CategoryName");
    return View();
}
<%using (Html.BeginForm("SelectListBox", "Control"))
  {%>
<fieldset>
    <legend>選擇類別</legend>
    <%=Html.ListBox("Category")%>
    <input type="submit" value="選擇"/>
</fieldset>
<%} %>

<form action="/Control/SelectListBox" method="post">
<fieldset>
    <legend>選擇類別</legend>
    <select id="Category" multiple="multiple" name="Category">
        <option value="1">Beverages</option>
        <option value="2">Condiments</option>
        <option value="3">Confections</option>
        <option value="4">Dairy Products</option>
        <option value="5">Grains/Cereals</option>
        <option value="6">Meat/Poultry</option>
        <option value="7">Produce</option>
        <option value="8">Seafood</option>
    </select>
    <input type="submit" value="選擇"/>
</fieldset>
</form>

當選中多項時,代碼如下:

public ActionResult SelectListBox(FormCollection form)
{
    var selectedCategories = form["Category"].Split(',').AsEnumerable();
    ViewData["SelectCategory"] = new MultiSelectList(db.Categories, "CategoryID", "CategoryName", selectedCategories);
    return View();
}
<%using (Html.BeginForm("ShowListBox", "Control"))
  {%>
<fieldset>
    <legend>當前選中類別</legend>
    <%=Html.ListBox("SelectCategory")%>
    <input type="submit" value="返回"/>
</fieldset>
<%} %>

<form action="/" method="post">
<fieldset>
    <legend>當前選中類別</legend>
    <select id="SelectCategory" multiple="multiple" name="SelectCategory">
        <option value="1">Beverages</option>
        <option selected="selected" value="2">Condiments</option>
        <option selected="selected" value="3">Confections</option>
        <option value="4">Dairy Products</option>
        <option value="5">Grains/Cereals</option>
        <option value="6">Meat/Poultry</option>
        <option value="7">Produce</option>
        <option value="8">Seafood</option>
    </select>
    <input type="submit" value="返回"/>
</fieldset>
</form>

TextAreaExtensions:設置文本域控件。重載方法列表:

TextArea(string name);
TextArea(string name,object htmlAttributes);
TextArea(string name,IDictionary<string,object> htmlAttributes);
TextArea(string name,string value);
TextArea(string name,string value,object htmlAttributes);
TextArea(string name,string value,IDictionary<string,object> htmlAttributes);
TextArea(string name,string value,int rows,int cols,object htmlAttributes);
TextArea(string name,string value,int rows,int cols,IDictionary<string,object> htmlAttributes);

我們先添加一個簡單的TextArea,默認情況下會生成2行10列:

Html.TextArea("description", "My name is miracle")
<textarea cols="20" id="description" name="description" rows="2">My name is miracle</textarea>

也可以指定行數和列數:

Html.TextArea("description", "My name is miracle", new { rows=5,cols=10 })
<textarea cols="10" id="description" name="description" rows="5">My name is miracle</textarea>

ValidationExtensions:實現表單控件的輸入驗證,包含ValidationMessage和ValidationSummary控件。

首先簡單的看一下ValidationMessage控件,重載方法列表:

ValidationMessage(string modelName);
ValidationMessage(string modelName,object htmlAttributes);
ValidationMessage(string modelName,string validationMessage);
ValidationMessage(string modelName,string validationMessage,object htmlAttributes);
ValidationMessage(string modelName,IDictionary<string,object> htmlAttributes);
ValidationMessage(string modelName,string validationMessage,IDictionary<string,object> htmlAttributes);
Html.TextBox("ProductName")
Html.ValidationMessage("ProductName", "*")

接下來看一下ValidationMessage和ValidationSummary的結合運用:

ValidationSummary();
ValidationSummary(string message);
ValidationSummary(string message,object htmlAttributes);
ValidationSummary(string message,IDictionary<string,object> htmlAttributes);

一般ValidationSummary應放在表單的外部:

<%=Html.ValidationSummary("創建不成功,請確認是否填寫正確!") %>
<%using (Html.BeginForm())
  {%>
<fieldset>
    <legend>輸入驗證</legend>
    <p>
        <label for="ProductName">名稱:</label>
        <%=Html.TextBox("ProductName")%>
        <%=Html.ValidationMessage("ProductName","*") %>
    </p>
    <p>
        <label for="Description">描述:</label>
        <%=Html.TextBox("Description")%>
        <%=Html.ValidationMessage("Description", "*")%>
    </p>
    <p>
        <label for="UnitPrice">單價:</label>
        <%=Html.TextBox("UnitPrice")%>
        <%=Html.ValidationMessage("UnitPrice", "*")%>
    </p>
    <p>
        <input type="submit" value="創建"/>
    </p>
</fieldset>
<%} %>

通常結合兩者使用,並在錯誤邏輯中加入ModelState,通過ModelState.IsValid判斷是否通過自定義驗證。

RenderPartialExtensions:實現將現有自定義控件或分部視圖加入到視圖,重載方法列表如下:

RenderPartial(string partialViewName);
RenderPartial(string partialViewName,ViewDataDictionary viewData);
RenderPartial(string partialViewName,object model);
RenderPartial(string partialViewName,object model,ViewDataDictionary viewData);

如將類別列表控件(CategoryList.ascx)加入到當前視圖:

Html.RenderPartial("CategoryList");


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM