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#的設計理念:讀著寫代碼。是的,使用擴充方法,我們的代碼可以像是完整的句子一樣被別人閱讀而不會在某個艱澀的地方戛然而止。
當然,濫用文法糖是一種危險的行為,畢竟擴充方法依然存在我剛才說的毛病,尤其是考慮軟體的後續發展,我們就會驚出一身冷汗:如果將來某個類型添加一個與我的擴充方法一樣的方法,那麼,My Code就會出錯。
所以,我們需要一種更加安全的方法。
三.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裡面。