一、一個功能強大的頁面開發輔助類—HtmlHelper初步瞭解
1.1 有失必有得
在ASP.Net MVC中微軟並沒有提供類似伺服器端控制元件那種開發方式,畢竟微軟的MVC就是傳統的請求處理響應的迴歸。所以拋棄之前的那種事件響應的模型,拋棄伺服器端控制元件也理所當然。
但是,如果手寫Html標籤效率又比較低,可重用度比較低。這時,我們該怎樣來提高效率呢?首先,經過上篇我們知道可以通過ViewData傳遞資料,於是我們可以寫出以下的Html程式碼:
1 |
<input name="UserName" type="text" value="<%: ViewData["UserName"] %>" /> |
雖然以上程式碼可以解決問題,但是效率還是比較低,特別是在列表集合項較多的時候,工作量會比較大。那麼,還有木有一種更好的方式呢?別急,微軟已經為我們想好了策略。微軟為開發人員快速開發前臺頁面提供了豐富的HtmlHelper的輔助類,輔助我們快速開發前臺頁面,也提供了可擴充套件的介面,前臺頁面的標籤可以可以做到高度可重用。
1.2 HtmlHelper初窺
我們可以通過在頁面中通過Html.XXX來實現快速的Html標籤編輯,並且可以方便地進行資料繫結。
1 |
<%: Html.Raw("<p>Hello,I am HtmlHelper!</p>") %> |
那麼,為什麼可以在頁面中呼叫Html.XXX方法呢?通過ILSpy反編譯ViewPage頁,我們可以看到原來在ViewPage下有一個HtmlHelper型別的屬性-Html。(這下終於知道,為什麼可以在頁面中使用Html.xxxx()了)
那麼這個HtmlHelper類又是一個什麼型別的大神呢?繼續反編譯檢視,在System.Web.Mvc名稱空間下的HtmlHelper型別如下圖所示,經過MSDN大神的講解,HtmlHelper支援在檢視中呈現 HTML 控制元件。那我們看看在此類中有木有傳說中的TextBox、CheckBox的方法呢?經檢視,木有。
那麼,我們為什麼可以在頁面中使用Html.TextBox()方法呢?這裡就涉及到一個叫做“擴充套件方法”的東東了,HtmlHelper 類的擴充套件方法在System.Web.Mvc.Html 名稱空間中。 這些擴充套件新增了用於建立窗體、呈現 HTML 控制元件、呈現分部檢視、執行輸入驗證等功能的幫助器方法。那麼,有關如何自定義擴充套件方法請參閱本文第三部分,這裡先賣個關子,暫不介紹。
1.3 為什麼使用HtmlHelper?
思考這樣一個場景:我們的專案第一個版本中的路由規則是這樣的{controller}/{action}/{id},於是我們專案中所有的<a>標籤所指向的都是以剛剛的規則命名的href(例如:<a href=’Home/User/1′></a>)。但是在第二版中,我們的路由規則也會變成了{controller}-{action}-{id},那麼我們剛剛為超連結所設定的href便都無法正常訪問了。這時,我們需要進行替換,單個替換或批量替換(例如改為:<a href=’Home-User-1′></a>),雖然也可以解決問題,但是無疑增加了工作量,效率很低。
那麼,怎樣來遮蔽這種變化所帶來的不便呢?這裡,通過使用HtmlHelper為我們提供的ActionLink標籤,便可以解決這個問題。因為HtmlHelper是從伺服器端自動幫你生成a標籤,因此所生成的href會遵循目前的路由規則,也就幫我們遮蔽了變化,提高了工作效率。
二、沒有伺服器控制元件也能幹大事—HtmlHelper重要方法介紹
PS:這裡的例項均沒有加<% %>或@符號,要執行請自行加上。
(1)ActionLink與RouteLink
1 2 3 4 5 6 7 8 9 10 |
Html.ActionLink("這是一個連線", "Index", "Home") 帶有QueryString的寫法 Html.ActionLink("這是一個連線", "Index", "Home", new { page=1 },null) Html.ActionLink("這是一個連線", "Index", new { page=1 }) 有其它Html屬性的寫法 Html.ActionLink("這是一個連線", "Index", "Home", new { id="link1" }) Html.ActionLink("這是一個連線", "Index",null, new { id="link1" }) QueryString與Html屬性同時存在 Html.ActionLink("這是一個連線", "Index", "Home", new { page = 1 }, new { id = "link1" }) Html.ActionLink("這是一個連線", "Index" , new { page = 1 }, new { id = "link1" }) |
其生成的結果為:
1 2 3 4 5 6 7 8 9 10 |
<a href="/">這是一個連線</a> 帶有QueryString的寫法 <a href="/?page=1">這是一個連線</a> <a href="/?page=1">這是一個連線</a> 有其它Html屬性的寫法 <a href="/?Length=4" id="link1">這是一個連線</a> <a href="/" id="link1">這是一個連線</a> QueryString與Html屬性同時存在 <a href="/?page=1" id="link1">這是一個連線</a> <a href="/?page=1" id="link1">這是一個連線</a> |
RouteLink在用法幾乎與ActionLink一致,這裡就不再介紹,詳情請參與MSDN;
(2)TextBox與TextArea
①TextBox
1 2 3 4 |
Html.TextBox("input1") Html.TextBox("input2",Model.CategoryName,new{ @style = "width:300px;" }) Html.TextBox("input3", ViewData["Name"],new{ @style = "width:300px;" }) Html.TextBoxFor(a => a.CategoryName, new { @style = "width:300px;" }) |
其生成的結果為:
1 2 3 4 |
<input id="input1" name="input1" type="text" value="" /> <input id="input2" name="input2" style="width:300px;" type="text" value="Beverages" /> <input id="input3" name="input3" style="width:300px;" type="text" value="" /> <input id="CategoryName" name="CategoryName" style="width:300px;" type="text" value="Electronic" /> |
②TextArea
1 2 |
Html.TextArea("input5", Model.CategoryName, 3, 9,null) Html.TextAreaFor(a => a.CategoryName, 3, 3, null) |
其生成的結果為:
1 2 |
<textarea cols="9" id="input5" name="input5" rows="3">Electronic</textarea> <textarea cols="3" id="CategoryName" name="CategoryName" rows="3">Electronic</textarea> |
這裡可以看到,我們可以使用強型別來生成Html標籤,例如:Html.TextBoxFor(a => a.CategoryName, new { @style = “width:300px;” }),這裡的CategoryName就是某個型別的屬性。
(3)CheckBox
1 2 3 |
Html.CheckBox("chk1",true) Html.CheckBox("chk1", new { @class="checkBox"}) Html.CheckBoxFor(a =>a.IsVaild, new { @class = "checkBox" }) |
其生成的結果為:
1 2 3 |
<input checked="checked" id="chk1" name="chk1" type="checkbox" value="true" /><input name="chk1" type="hidden" value="false" /> <input class="checkBox" id="chk1" name="chk1" type="checkbox" value="true" /><input name="chk1" type="hidden" value="false" /> <input checked="checked" class="checkBox" id="IsVaild" name="IsVaild" type="checkbox" value="true" /><input name="IsVaild" type="hidden" value="false" /> |
(4)DropDownList
1 2 |
Html.DropDownList("ddl1", (SelectList)ViewData["Categories"], "--Select One--") Html.DropDownListFor(a => a.CategoryName, (SelectList)ViewData["Categories"], "--Select One--", new { @class = "dropdownlist" }) |
其生成的結果為:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<select id="ddl1" name="ddl1"> <option value="">--Select One--</option> <option value="1">Beverages</option> <option 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> <select class="dropdownlist" id="CategoryName" name="CategoryName"> <option value="">--Select One--</option> <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> |
(5)RadioButton
1 2 |
男<%: Html.RadioButton("Gender","1",true) %> 女<%: Html.RadioButton("Gender","2",false) %> |
其生成的程式碼為:
1 2 |
男<input checked="checked" id="Gender" name="Gender" type="radio" value="1" /> 女<input id="Gender" name="Gender" type="radio" value="2" /> |
(6)Encode與Raw
Encode會將內容進行編碼話,因此,如果你的內容中含有Html標籤的話那麼會被解析成特殊字元,例如:
1 |
<%: Html.Encode("<p>哈哈</p>") %> |
其生成的程式碼為:
1 |
&lt;p&gt;哈哈&lt;/p&gt; |
這裡主要是為了防止XSS攻擊和惡意指令碼,因此在MVC中,預設的<%: %>就實現了<%: Html.Encode() %>。但是,某些時候如果我們需要輸出Html或JavaScript內容的字串,這時我們可以使用HtmlHelper為我們提供的其他方法。例如我們要輸出剛剛那句話,我們可以如下使用:
1 |
<%: Html.Raw("<p>哈哈</p>") %> |
其生成的程式碼為:
1 |
<p>哈哈</p> |
在HtmlHelper中還提供了許多的擴充套件方法供我們方便建立Html,比如:BeginForm、EndForm等。關於其他的方法介紹,請自行搜尋,這裡不再一一贅述。
三、隨時隨地我也能擴充套件—HtmlHelper擴充套件方法簡介
3.1 擴充套件方法簡介
藉助MSDN的介紹:“擴充套件方法使你能夠向現有型別“新增”方法,而無需建立新的派生型別、重新編譯或以其他方式修改原始型別。”擴充套件方法是一種特殊的靜態方法,但可以像擴充套件型別上的例項方法一樣進行呼叫。我們可以回到第一部分對HtmlHelper的擴充套件類-InputExtension類上,它是對於HtmlHelper的擴充套件,那麼怎麼鑑別它是HtmlHelper的擴充套件呢?
3.2 擴充套件方法的三要素
(1)靜態類
可以從上圖看出,InputExtension首先是一個靜態類;
(2)靜態方法
既然是靜態類,那麼其所有的方法必然都是靜態方法,例如:public static MvcHtmlString CheckBox();
(3)this關鍵字
可以從方法名定義中看出,第一個引數都是this HtmlHelper htmlHelper,代表對HtmlHelper類的擴充套件;
3.3 自定義擴充套件方法
(1)在Models資料夾下新建一個類,取名為:MyHtmlHelperExt
(2)將MyHtmlHelperExt設定為static,並寫入以下的一個靜態方法:
1 2 3 4 |
public static HtmlString MyExtHtmlLabel(this HtmlHelper helper, string value) { return new HtmlString(string.Format("<span style='font-weight:bold;'>Hello-{0}-End</span>", value)); } |
(3)確定滿足了擴充套件方法的三要素之後,將名稱空間改為:System.Web.Mvc。
1 |
namespace System.Web.Mvc |
PS:為什麼要改名稱空間為System.Web.Mvc?
這是因為如果不改名稱空間,我們要使用自定義的擴充套件方法需要在每個頁面中引入Models(MyHtmlHelper所在的那個名稱空間)這個名稱空間,為了防止重複的名稱空間引入操作(想想我們使用Html.TextBox()不也沒有引入名稱空間麼?),於是我們將名稱空間與HtmlHelper類所在的名稱空間保持一致。
(4)在頁面中我們就可以使用我們自己寫的擴充套件方法了
1 |
<%: Html.MyExtHtmlLabel("EdisonChou") %> |
(5)檢視頁面效果
參考文章
(1)馬倫,《ASP.Net MVC視訊教程》,http://bbs.itcast.cn/thread-26722-1-1.html
(2)oer,《HtmlHelper使用大全》,http://www.cnblogs.com/oer2001/archive/2013/03/19/2968475.html
(3)MSDN,《擴充套件方法(C#程式設計指南)》,http://technet.microsoft.com/zh-cn/bb383977
(4)MSDN,《HtmlHelper類(System.Web.Mvc)》,http://msdn.microsoft.com/zh-cn/library/system.web.mvc.htmlhelper(v=vs.108).aspx