MVC3 ActionLink с изображениями (но без MvcFutures)?

Мне было интересно, если кто-нибудь знает, возможно ли использовать "из коробки" помощников ASP.NET MVC3 для создания "кнопки ссылки"... В настоящее время я использую следующее:

<a class="button" title="My Action" href="@Url.Action("MyAction", "MyController", new { id = item.Id })">
    <img alt="My Action" src="@Url.Content("~/Content/Images/MyLinkImage.png")" />
</a>

Я пытаюсь избегать использования MvcFutures, но даже если бы я смог их использовать, я не думаю, что есть способ расширения, который бы это тоже достиг. (Я полагаю, что решением в этом случае будет накатить пользовательский помощник, как показано здесь)

Наконец, в этом посте также есть хорошая идея справиться с этим через CSS, но я не об этом...

3 ответа

Решение

Я использую следующее для создания ссылок действий:

using System;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
using Fasterflect;

namespace Stackru.Mvc.Extensions
{
    public static class HtmlExtensions
    {
        #region ActionImage
        // href image link
        public static string ActionImage( this HtmlHelper helper, string href, string linkText, object htmlAttributes,
                                          string alternateText, string imageSrc, object imageAttributes )
        {
            var sb = new StringBuilder();
            const string format = "<a href=\"{0}\"{1}>{2}</a>";
            string image = helper.Image( imageSrc, alternateText, imageAttributes ).ToString();
            string content = string.IsNullOrWhiteSpace( linkText ) ? image : image + linkText;
            sb.AppendFormat( format, href, GetAttributeString( htmlAttributes ), content );
            return sb.ToString();
        }

        // controller/action image link
        public static string ActionImage( this HtmlHelper helper, string controller, string action, string linkText, object htmlAttributes,
                                          string alternateText, string imageSrc, object imageAttributes )
        {
            bool isDefaultAction = string.IsNullOrEmpty( action ) || action == "Index";
            string href = "/" + (controller ?? "Home") + (isDefaultAction ? string.Empty : "/" + action);
            return ActionImage( helper, href, linkText, htmlAttributes, alternateText, imageSrc, imageAttributes );
        }

        // T4MVC ActionResult image link
        public static string ActionImage( this HtmlHelper helper, ActionResult actionResult, string linkText, object htmlAttributes,
                                          string alternateText, string imageSrc, object imageAttributes )
        {
            var controller = (string) actionResult.GetPropertyValue( "Controller" );
            var action = (string) actionResult.GetPropertyValue( "Action" );
            return ActionImage( helper, controller, action, linkText, htmlAttributes, alternateText, imageSrc, imageAttributes );
        }       
        #endregion

        #region Helpers
        private static string GetAttributeString( object htmlAttributes )
        {
            if( htmlAttributes == null )
            {
                return string.Empty;
            }
            const string format = " {0}=\"{1}\"";
            var sb = new StringBuilder();
            htmlAttributes.GetType().Properties().ForEach( p => sb.AppendFormat( format, p.Name, p.Get( htmlAttributes ) ) );
            return sb.ToString();
        }       
        #endregion
    }
}

Обратите внимание, что метод GetAttributeString опирается на библиотеку Fasterflect, чтобы упростить задачи отражения, но вы можете заменить это регулярным отражением, если предпочитаете не брать дополнительную зависимость.

Вспомогательное расширение Image раньше было частью MvcContrib, но, похоже, было удалено, скорее всего потому, что теперь функциональность встроена в MVC. Несмотря на это, я включил его ниже для полноты:

public static class ImageExtensions {
    public static MvcHtmlString Image(this HtmlHelper helper, string imageRelativeUrl, string alt, object htmlAttributes) {
        return Image(helper, imageRelativeUrl, alt, new RouteValueDictionary(htmlAttributes));
    }

    public static MvcHtmlString Image(this HtmlHelper helper, string imageRelativeUrl, string alt, IDictionary<string, object> htmlAttributes) {
        if (String.IsNullOrEmpty(imageRelativeUrl)) {
            throw new ArgumentException(MvcResources.Common_NullOrEmpty, "imageRelativeUrl");
        }

        string imageUrl = UrlHelper.GenerateContentUrl(imageRelativeUrl, helper.ViewContext.HttpContext);
        return MvcHtmlString.Create(Image(imageUrl, alt, htmlAttributes).ToString(TagRenderMode.SelfClosing));
    }

    public static TagBuilder Image(string imageUrl, string alt, IDictionary<string, object> htmlAttributes) {
        if (String.IsNullOrEmpty(imageUrl)) {
            throw new ArgumentException(MvcResources.Common_NullOrEmpty, "imageUrl");
        }

        TagBuilder imageTag = new TagBuilder("img");

        if (!String.IsNullOrEmpty(imageUrl)) {
            imageTag.MergeAttribute("src", imageUrl);
        }

        if (!String.IsNullOrEmpty(alt)) {
            imageTag.MergeAttribute("alt", alt);
        }

        imageTag.MergeAttributes(htmlAttributes, true);

        if (imageTag.Attributes.ContainsKey("alt") && !imageTag.Attributes.ContainsKey("title")) {
            imageTag.MergeAttribute("title", (imageTag.Attributes["alt"] ?? "").ToString());
        }
        return imageTag;
    }
}

Фрагмент у вас выглядит довольно хорошо. Вы должны обернуть это в вспомогательный помощник html общего назначения и назвать это днем. Я уверен, что в вашем приложении есть и другие, более интересные аспекты, чем придирчивость к помощникам пользовательского интерфейса:)

Проверьте в нижней части этого блога пример использования методов расширения HTML от Стивена Вальтера.

Другие вопросы по тегам