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)查看頁面效果
參考文章: http://blog.jobbole.com/84997/
(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