вторник, 9 ноября 2010 г.

Методы расширения на примере кастомного HmtlHelper'а

Столкнулась сегодня с весьма необычной конструкцией программирования: методом расширения (Extension Methods). Коротенько: используется она для того, чтобы добавить методы к расширяемому классу, используя описание какбэ "наследника", и является разновидностью статического метода. Т.е. идея состоит в чем: есть класс с кучей статических методов, вы хотите добавить к нему горстку своих, следовательно, надо создать наследника и расширить его дополнительными методами, но мы по каким-то причинам не хотим захламлять код новыми названиями стандартных классов, поэтому мы новые методы делаем методами расширения, и уже на практике используем для их вызова имя стандартного класса. Я прочувствовала это при кастумизации HtmlHelper'а в Asp.Net. И хочу поделиться не только примером того, как я в разметке страницы оформляю менюшку-картинку-ссылку, но еще акцентировать внимание на этот забавный и приятный метод программирования.

Синтаксическое отличие метода расширения от обычного статического метода заключается в наличии дополнительного первого параметра: его тип является типом, который мы расширяем, и спереди указывается ключевое слово this. Далее статический класс, в котором мы реализовали свои гениальные методы, заключаем в некий namespace, который в свою очередь в нужный модуль подключаем при помощи директивы using (или если это aspx-страница, то при помощи директивы Import) - и чудо готово! Расширенный класс (тип которого мы указали первым параметром) теперь будет виден IntelliSense с новыми методами!

А теперь про конкретный пример. Я сейчас использую библиотеку mvc2 и Asp.Net 4.0. Дабы разработчики не задротствовали с указанием ссылок, майкрософт подарила статический метод ActionLink у класса HtmlHelper. Но мне нужна не текстовая ссылка, а ссылка картинкой - менюшка. Я не люблю использовать для этого тег img, потому что адрес картинки к нему указывается через атрибут src, а я люблю задавать все графические ресурсы через background в таблице стилей asp.net темы, и следовательно хранятся они в дочерней папке этой темы. И к тому же, как правило, когда у меня меню оформляется в виде картинок, это значит, что оно на необычном месте (к примеру, тот же самый лого), т.е. задается фиксированными координатами, position:absolute and so on. Поэтому я предпочитаю на странице оставлять некий голый тэг без атрибутов, указывая только его класс. И для этих нужд мне идеально подходит тег div.
Поэтому я хотела создать HtmlHelper, которрый бы выводил на страницу див с заданным классом в объятиях ссылки на определенный экшен определенного контроллера.
Вот его код:
using System.Web.Mvc;
using System.Web.Routing;
 
namespace HtmlHelpers
{
    public static class Helpers
    {
        public static string ImageLink(this HtmlHelper helper, string controller, string action, string title, string cssclass)
        {
            var urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
            var link = new TagBuilder("a");
            link.MergeAttribute("href", urlHelper.Action(action, controller));
            link.MergeAttribute("title", title);
            var div = new TagBuilder("div");
            div.AddCssClass(cssclass);
            link.InnerHtml = div.ToString(TagRenderMode.Normal);
            return link.ToString(TagRenderMode.Normal);
        }   
    }
}

А теперь эталонной странице (MasterPage) я прописываю директиву импорта с моим нэймспэйсом: <%@ Import Namespace="HtmlHelpers" %> и со спокойной совестью прописываю логотип скриплетом: <%= Html.ImageLink("Home","Index", "На главную","LogoLink") %>

Вот и всё :) Да здравствуют элегантность, грация и красота в разметке страницы :)

3 комментария:

  1. Да :D Любит радовать приятными неожиданностями :D

    ОтветитьУдалить
  2. эмм...ну как минимум, когда принемаешь этот метод, то он возвращает строчку тега, который тупо вставляется и не конвертится в HTML. Или я не прав?

    ОтветитьУдалить