ASP.NET MVC---自定义HtmlHelper方法

       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里面。


     

    

posted @ 2013-03-30 19:41  文酱  阅读(10353)  评论(6编辑  收藏  举报