HtmlHelper方法是ASP.NET MVC中非常強大的特性,有了這個特性,我們就能更加隨心所欲的定制自己的頁面。
自定義自己的HtmlHelper方法通常有三種, 像是:
一.Razor語法
采用Razor的方式非常直觀,像是這樣:
@model IEnumerable<MusicShop.Models.Album> @{ ViewBag.Title = "Index"; } @helper Truncate(string input, int length) { if (input.Length <= length) { @input; } else { @input.Substring(0, length)<text>...</text>; } } <h2>Index</h2> <p> @Html.ActionLink("Create New", "Create") </p> <table> <tr> <th> Genre </th> <th> Artist </th> <th> Title </th> <th> Price </th> <th> AlbumArtUrl </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Genre.Name) </td> <td> @Truncate(item.Artist.Name, 25); </td> <td> @Truncate(item.Title, 25); </td> <td> @Html.DisplayFor(modelItem => item.Price) </td> <td> @Html.DisplayFor(modelItem => item.AlbumArtUrl) </td> <td> @Html.ActionLink("Edit", "Edit", new { id=item.AlbumId }) | @Html.ActionLink("Details", "Details", new { id=item.AlbumId }) | @Html.ActionLink("Delete", "Delete", new { id=item.AlbumId }) </td> </tr> } </table>
@helper提示編譯器,這是一個輔助方法,我們可以采用@+MethodName的方法來使用該輔助方法。
當然,在Web編程中,內聯是一種不好的方式,因為它們會使得頁面的加載變慢,尤其是頁面的反復加載。更加常用的方式就是我們在一個命名空間里定義一個輔助方法,然后在頁面中引入該輔助方法,這樣頁面就無需承擔方法源碼的加載負擔。
二.擴展方法
采用這樣的方式,我們通常需要新建一個文件夾,專門存放我們自定義的輔助方法(很多時候,我們自定義的輔助方法可能很多,但像是Controller,Models這樣的文件夾並不適合存放這些方法),其實也就是專門為輔助方法建立一個新的命名空間。
像是這樣:
using System; using System.Collections.Generic; using System.Linq; using System.Web.Mvc; namespace MusicShop.Helpers { public static class HtmlHelpers { public static string Truncate(this HtmlHelper helper, string input, int length) { if (input.Length <= length) { return input; } else { return input.Substring(0, length) + "..."; } } } }
然后我們的頁面添加以下的代碼:
@model IEnumerable<MusicShop.Models.Album> @{ ViewBag.Title = "Index"; } @using MusicShop.Helpers <h2>Index</h2> <p> @Html.ActionLink("Create New", "Create") </p> <table> <tr> <th> Genre </th> <th> Artist </th> <th> Title </th> <th> Price </th> <th> AlbumArtUrl </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Genre.Name) </td> <td> @Html.Truncate(item.Artist.Name, 25); </td> <td> @Html.Truncate(item.Title, 25); </td> <td> @Html.DisplayFor(modelItem => item.Price) </td> <td> @Html.DisplayFor(modelItem => item.AlbumArtUrl) </td> <td> @Html.ActionLink("Edit", "Edit", new { id=item.AlbumId }) | @Html.ActionLink("Details", "Details", new { id=item.AlbumId }) | @Html.ActionLink("Delete", "Delete", new { id=item.AlbumId }) </td> </tr> } </table>
@using是必須的,引入輔助方法所在的命名空間。對於輔助方法的處理可以看到,我們是將其當成HtmlHelper的擴展方法使用。擴展方法的使用,使得原本非常復雜的MVC設計也能具有良好的可讀性,而且靈活度和復用性非常高。我剛學C#的時候,曾經對擴展方法並不是特別感冒,因為它的使用很容易"污染"被擴展類型的命名空間,使得我們在查找該類型方法的時候非常煩。但是在使用MVC的時候,尤其是HtmlHelper方法的時候,擴展方法給了我很大的震驚:如果沒有擴展方法,整個代碼的可讀性真的很可怕!這時我想起來C#的設計理念:讀着寫代碼。是的,使用擴展方法,我們的代碼可以像是完整的句子一樣被別人閱讀而不會在某個艱澀的地方戛然而止。
當然,濫用語法糖是一種危險的行為,畢竟擴展方法依然存在我剛才說的毛病,尤其是考慮軟件的后續發展,我們就會驚出一身冷汗:如果將來某個類型添加一個與我的擴展方法一樣的方法,那么,我的代碼就會出錯。
所以,我們需要一種更加安全的方法。
三.Razor view
我們可以新建一個cshtml,像是下面這樣:
@helper TruncateString(string input, int length) { if (input.Length <= length) { @input } else { @input.Substring(0, length)<text>...</text> } }
然后就是我們的頁面:
@model IEnumerable<MusicShop.Models.Album> @{ ViewBag.Title = "Index"; } <h2>Index</h2> <p> @Html.ActionLink("Create New", "Create") </p> <table> <tr> <th> Genre </th> <th> Artist </th> <th> Title </th> <th> Price </th> <th> AlbumArtUrl </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Genre.Name) </td> <td> @Helpers.Truncate(item.Artist.Name, 25); </td> <td> @Helpers.Truncate(item.Title, 25); </td> <td> @Html.DisplayFor(modelItem => item.Price) </td> <td> @Html.DisplayFor(modelItem => item.AlbumArtUrl) </td> <td> @Html.ActionLink("Edit", "Edit", new { id=item.AlbumId }) | @Html.ActionLink("Details", "Details", new { id=item.AlbumId }) | @Html.ActionLink("Delete", "Delete", new { id=item.AlbumId }) </td> </tr> } </table>
使用這種方法,就沒有Razor語法的內聯,也沒有擴展方法的后顧之憂,而且我們還可以自由的添加新的自定義方法,但是,注意,Helpers.cshtml必須放在App_Code里面。