Rasoir Action Image MVC3

119

Quelle est la meilleure façon de remplacer les liens par des images à l'aide de Razor dans MVC3. Je fais simplement ceci pour le moment:

<a href="@Url.Action("Edit", new { id=MyId })"><img src="../../Content/Images/Image.bmp", alt="Edit" /></a> 

Y a-t-il un meilleur moyen?

Davy
la source
15
Pas directement lié, mais je vous suggère fortement d'utiliser des fichiers PNG ou JPG (selon le contenu de l'image) au lieu de fichiers BMP. Et comme @jgauffin l'a suggéré, essayez également d'utiliser les chemins relatifs de l'application ( ~/Content). Le chemin ../../Contentpourrait ne pas être valide de différentes voies (par exemple /, /Home, /Home/Index).
Lucas le
Merci Lucas. J'utilise png mais le conseil pour utiliser URL.Content est ce que je recherchais. vote up :)
davy

Réponses:

217

Vous pouvez créer une méthode d'extension pour HtmlHelper afin de simplifier le code dans votre fichier CSHTML. Vous pouvez remplacer vos balises par une méthode comme celle-ci:

// Sample usage in CSHTML
@Html.ActionImage("Edit", new { id = MyId }, "~/Content/Images/Image.bmp", "Edit")

Voici un exemple de méthode d'extension pour le code ci-dessus:

// Extension method
public static MvcHtmlString ActionImage(this HtmlHelper html, string action, object routeValues, string imagePath, string alt)
{
    var url = new UrlHelper(html.ViewContext.RequestContext);

    // build the <img> tag
    var imgBuilder = new TagBuilder("img");
    imgBuilder.MergeAttribute("src", url.Content(imagePath));
    imgBuilder.MergeAttribute("alt", alt);
    string imgHtml = imgBuilder.ToString(TagRenderMode.SelfClosing);

    // build the <a> tag
    var anchorBuilder = new TagBuilder("a");
    anchorBuilder.MergeAttribute("href", url.Action(action, routeValues));
    anchorBuilder.InnerHtml = imgHtml; // include the <img> tag inside
    string anchorHtml = anchorBuilder.ToString(TagRenderMode.Normal);

    return MvcHtmlString.Create(anchorHtml);
}
Lucas
la source
5
Excellent extrait. Toute personne souhaitant l'utiliser avec T4MVC doit simplement changer le type de routeValuesà ActionResult, puis dans la url.Actionfonction, changer routeValuesenrouteValues.GetRouteValueDictionary()
JConstantine
12
@Kasper Skov: placez la méthode dans une classe statique, puis référencez l'espace de noms de cette classe dans le Web.config de l' /configuration/system.web/pages/namespacesélément.
Umar Farooq Khawaja
4
Nice !, au lieu de alt, j'accepte un objet pour recevoir des propriétés html en utilisant un objet anonyme puis var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);et enfinforeach (var attr in attributes){ imgBuilder.MergeAttribute(attr.Key, attr.Value.ToString());}
guzart
7
Je n'ai pas pu faire fonctionner cela jusqu'à ce que je réalise que, parce que j'utilise Areas, une référence à l'espace de noms de la classe (comme indiqué par Umar) doit être ajoutée à TOUS les fichiers web.config dans le dossier Views pour toutes les zones ainsi que le /Viewsdossier de niveau supérieur
Mark_Gibson
2
Si vous n'en avez besoin que dans une seule page, au lieu de modifier les fichiers Web.config, vous pouvez ajouter une instruction @using dans le .cshtml et référencer l'espace de noms
JML
64

Vous pouvez utiliser Url.Contentce qui fonctionne pour tous les liens car il traduit le tilde ~en uri racine.

<a href="@Url.Action("Edit", new { id=MyId })">
    <img src="@Url.Content("~/Content/Images/Image.bmp")", alt="Edit" />
</a>
jgauffin
la source
3
Cela fonctionne très bien dans MVC3. Je vous remercie! <a href="@Url.Action("Index","Home")"><img src="@Url.Content("~/Content/images/myimage.gif")" alt="Home" /></a>
rk1962
24

S'appuyant sur la réponse de Lucas ci-dessus, il s'agit d'une surcharge qui prend un nom de contrôleur comme paramètre, similaire à ActionLink. Utilisez cette surcharge lorsque votre image est liée à une action dans un contrôleur différent.

// Extension method
public static MvcHtmlString ActionImage(this HtmlHelper html, string action, string controllerName, object routeValues, string imagePath, string alt)
{
    var url = new UrlHelper(html.ViewContext.RequestContext);

    // build the <img> tag
    var imgBuilder = new TagBuilder("img");
    imgBuilder.MergeAttribute("src", url.Content(imagePath));
    imgBuilder.MergeAttribute("alt", alt);
    string imgHtml = imgBuilder.ToString(TagRenderMode.SelfClosing);

    // build the <a> tag
    var anchorBuilder = new TagBuilder("a");

    anchorBuilder.MergeAttribute("href", url.Action(action, controllerName, routeValues));
    anchorBuilder.InnerHtml = imgHtml; // include the <img> tag inside
    string anchorHtml = anchorBuilder.ToString(TagRenderMode.Normal);

    return MvcHtmlString.Create(anchorHtml);
}
Crake
la source
1
pas de commentaire sur votre ajouter ici ... enfin je dis bonne modification du code donné. +1 de moi.
Zack Jannsen
11

Eh bien, vous pouvez utiliser la solution @Lucas, mais il existe également un autre moyen.

 @Html.ActionLink("Update", "Update", *Your object value*, new { @class = "imgLink"})

Maintenant, ajoutez cette classe sur un fichier CSS ou dans votre page:

.imgLink
{
  background: url(YourImage.png) no-repeat;
}

Avec cette classe, tout lien aura l'image souhaitée.

AdrianoRR
la source
2
@KasperSkov J'ai oublié ce petit problème. Pour une raison quelconque, ce remplacement particulier de l'aide actionLink ne fonctionne pas avec l'exemple ci-dessus. Vous devez le ControllerNamede votre action. Comme ça:@Html.ActionLink("Update", "Update", "*Your Controller*",*object values*, new {@class = "imgLink"})
AdrianoRR
3

Cela s'est avéré être un fil très utile.

Pour ceux qui sont allergiques aux accolades, voici la version VB.NET des réponses de Lucas et Crake:

Public Module ActionImage
    <System.Runtime.CompilerServices.Extension()>
    Function ActionImage(html As HtmlHelper, Action As String, RouteValues As Object, ImagePath As String, AltText As String) As MvcHtmlString

        Dim url = New UrlHelper(html.ViewContext.RequestContext)

        Dim imgHtml As String
        'Build the <img> tag
        Dim imgBuilder = New TagBuilder("img")
        With imgBuilder
            .MergeAttribute("src", url.Content(ImagePath))
            .MergeAttribute("alt", AltText)
            imgHtml = .ToString(TagRenderMode.Normal)
        End With

        Dim aHtml As String
        'Build the <a> tag
        Dim aBuilder = New TagBuilder("a")
        With aBuilder
            .MergeAttribute("href", url.Action(Action, RouteValues))
            .InnerHtml = imgHtml 'Include the <img> tag inside
            aHtml = aBuilder.ToString(TagRenderMode.Normal)
        End With

        Return MvcHtmlString.Create(aHtml)

    End Function

    <Extension()>
    Function ActionImage(html As HtmlHelper, Action As String, Controller As String, RouteValues As Object, ImagePath As String, AltText As String) As MvcHtmlString

        Dim url = New UrlHelper(html.ViewContext.RequestContext)

        Dim imgHtml As String
        'Build the <img> tag
        Dim imgBuilder = New TagBuilder("img")
        With imgBuilder
            .MergeAttribute("src", url.Content(ImagePath))
            .MergeAttribute("alt", AltText)
            imgHtml = .ToString(TagRenderMode.Normal)
        End With

        Dim aHtml As String
        'Build the <a> tag
        Dim aBuilder = New TagBuilder("a")
        With aBuilder
            .MergeAttribute("href", url.Action(Action, Controller, RouteValues))
            .InnerHtml = imgHtml 'Include the <img> tag inside
            aHtml = aBuilder.ToString(TagRenderMode.Normal)
        End With

        Return MvcHtmlString.Create(aHtml)

    End Function

End Module
dansan
la source
1

Cette méthode d'extension fonctionne également (à placer dans une classe statique publique):

    public static MvcHtmlString ImageActionLink(this AjaxHelper helper, string imageUrl, string altText, string actionName, object routeValues, AjaxOptions ajaxOptions)
    {
        var builder = new TagBuilder("img");
        builder.MergeAttribute("src", imageUrl);
        builder.MergeAttribute("alt", altText);
        var link = helper.ActionLink("[replaceme]", actionName, routeValues, ajaxOptions);
        return new MvcHtmlString( link.ToHtmlString().Replace("[replaceme]", builder.ToString(TagRenderMode.SelfClosing)) );
    }
Diego
la source
1

Pour ajouter à tout le travail impressionnant commencé par Luke, j'en publie un de plus qui prend une valeur de classe css et traite la classe et l'alt comme des paramètres optionnels (valide sous ASP.NET 3.5+). Cela permettra plus de fonctionnalités mais réduira le nombre de méthodes surchargées nécessaires.

// Extension method
    public static MvcHtmlString ActionImage(this HtmlHelper html, string action,
        string controllerName, object routeValues, string imagePath, string alt = null, string cssClass = null)
    {
        var url = new UrlHelper(html.ViewContext.RequestContext);

        // build the <img> tag
        var imgBuilder = new TagBuilder("img");
        imgBuilder.MergeAttribute("src", url.Content(imagePath));
        if(alt != null)
            imgBuilder.MergeAttribute("alt", alt);
        if (cssClass != null)
            imgBuilder.MergeAttribute("class", cssClass);

        string imgHtml = imgBuilder.ToString(TagRenderMode.SelfClosing);

        // build the <a> tag
        var anchorBuilder = new TagBuilder("a");

        anchorBuilder.MergeAttribute("href", url.Action(action, controllerName, routeValues));
        anchorBuilder.InnerHtml = imgHtml; // include the <img> tag inside
        string anchorHtml = anchorBuilder.ToString(TagRenderMode.Normal);

        return MvcHtmlString.Create(anchorHtml);
    }
Zack Jannsen
la source
Aussi, pour tous ceux qui découvrent MVC, un conseil utile - la valeur de routeValue doit être @ RouteTable.Routes ["Home"] ou quel que soit votre identifiant "route" dans la RouteTable.
Zack Jannsen
1

modification de la diapositive modifiée Helper

     public static IHtmlString ActionImageLink(this HtmlHelper html, string action, object routeValues, string styleClass, string alt)
    {
        var url = new UrlHelper(html.ViewContext.RequestContext);
        var anchorBuilder = new TagBuilder("a");
        anchorBuilder.MergeAttribute("href", url.Action(action, routeValues));
        anchorBuilder.AddCssClass(styleClass);
        string anchorHtml = anchorBuilder.ToString(TagRenderMode.Normal);

        return new HtmlString(anchorHtml);
    }

Classe CSS

.Edit {
       background: url('../images/edit.png') no-repeat right;
       display: inline-block;
       height: 16px;
       width: 16px;
      }

Créez le lien, passez simplement le nom de la classe

     @Html.ActionImageLink("Edit", new { id = item.ID }, "Edit" , "Edit") 
dnxit
la source
0

J'ai joint la réponse de Lucas et " ASP.NET MVC Helpers, fusion de deux objets htmlAttributes ensemble " et plus controllerName au code suivant:

// Exemple d'utilisation dans CSHTML

 @Html.ActionImage("Edit",
       "EditController"
        new { id = MyId },
       "~/Content/Images/Image.bmp",
       new { width=108, height=129, alt="Edit" })

Et la classe d'extension pour le code ci-dessus:

using System.Collections.Generic;
using System.Reflection;
using System.Web.Mvc;

namespace MVC.Extensions
{
    public static class MvcHtmlStringExt
    {
        // Extension method
        public static MvcHtmlString ActionImage(
          this HtmlHelper html,
          string action,
          string controllerName,
          object routeValues,
          string imagePath,
          object htmlAttributes)
        {
            ///programming/4896439/action-image-mvc3-razor
            var url = new UrlHelper(html.ViewContext.RequestContext);

            // build the <img> tag
            var imgBuilder = new TagBuilder("img");
            imgBuilder.MergeAttribute("src", url.Content(imagePath));

            var dictAttributes = htmlAttributes.ToDictionary();

            if (dictAttributes != null)
            {
                foreach (var attribute in dictAttributes)
                {
                    imgBuilder.MergeAttribute(attribute.Key, attribute.Value.ToString(), true);
                }
            }                        

            string imgHtml = imgBuilder.ToString(TagRenderMode.SelfClosing);

            // build the <a> tag
            var anchorBuilder = new TagBuilder("a");
            anchorBuilder.MergeAttribute("href", url.Action(action, controllerName, routeValues));
            anchorBuilder.InnerHtml = imgHtml; // include the <img> tag inside            
            string anchorHtml = anchorBuilder.ToString(TagRenderMode.Normal);

            return MvcHtmlString.Create(anchorHtml);
        }

        public static IDictionary<string, object> ToDictionary(this object data)
        {
            ///programming/6038255/asp-net-mvc-helpers-merging-two-object-htmlattributes-together

            if (data == null) return null; // Or throw an ArgumentNullException if you want

            BindingFlags publicAttributes = BindingFlags.Public | BindingFlags.Instance;
            Dictionary<string, object> dictionary = new Dictionary<string, object>();

            foreach (PropertyInfo property in
                     data.GetType().GetProperties(publicAttributes))
            {
                if (property.CanRead)
                {
                    dictionary.Add(property.Name, property.GetValue(data, null));
                }
            }
            return dictionary;
        }
    }
}
Tomas Kubes
la source
0

Ce serait très bien fonctionner

<a href="<%:Url.Action("Edit","Account",new {  id=item.UserId }) %>"><img src="../../Content/ThemeNew/images/edit_notes_delete11.png" alt="Edit" width="25px" height="25px" /></a>
user3181441
la source