2011-02-04 20 views
117

¿Cuál es la mejor manera de reemplazar enlaces con imágenes usando Razor en MVC3. Simplemente estoy haciendo esto en este momento:Action Image MVC3 Razor

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

¿Hay una manera mejor?

+15

No relacionado directamente, pero le sugiero que use archivos PNG o JPG (dependiendo del contenido de la imagen) en su lugar o f archivos BMP. Y como se sugirió @jgauffin, también intente utilizar rutas relativas de aplicación ('~/Content'). La ruta '../../ Content' podría no ser válida desde diferentes rutas (por ejemplo,'/','/Home', '/ Home/Index'). – Lucas

+0

Gracias Lucas. Utilizo png pero el consejo para usar URL.Content es lo que estaba buscando. vote up :) – davy

Respuesta

215

Puede crear un método de extensión para HtmlHelper para simplificar el código en su archivo CSHTML. Podría reemplazar las etiquetas con un método como este:

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

Aquí es un método de extensión de la muestra para el código anterior:

// 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); 
} 
+1

+1 para proporcionar una solución tan elegante. – vbocan

+0

Esto es bueno, también agregué una sobrecarga que le permite especificar el controlador para la acción. ¡Buen trabajo! – Banford

+0

Muy agradable. Aprendí mucho en ese párrafo que publicó :) – Yablargo

63

Puede usar Url.Content que funcione para todos los enlaces, ya que traduce la tilde ~ al uri raíz.

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

Esto funciona muy bien en MVC3. ¡Gracias! 'Home' – rk1962

11

Bueno, se podría utilizar la solución @Lucas, pero también hay otra manera .

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

Ahora, agregue esta clase en un archivo CSS o en su página:

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

Con esa clase, cualquier enlace tendrá la imagen deseada.

+0

No funciona. La salida es:? Length = 5 –

+2

@KasperSkov Olvidé este pequeño problema. Por alguna razón, esta anulación particular de actionLink helper, no funciona con el ejemplo anterior. Tienes que tener el 'ControllerName' de tu acción. De esta manera: '@ Html.ActionLink (" Actualizar "," Actualizar "," * Su controlador * ", * valores de objeto *, nuevo {@class =" imgLink "})' – AdrianoRR

+0

Ah bien, veo .. –

1

Este método de extensión también funciona (para ser colocado en una clase public static):

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))); 
    } 
22

Sobre la base de la respuesta de Lucas anteriormente, esta es una sobrecarga que toma un nombre de controlador como parámetro, similar a ActionLink. Use esta sobrecarga cuando su imagen se vincule a una Acción en un controlador diferente.

// 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); 
} 
+1

no hay comentarios en su agregar aquí ... bueno digo buena modificación al código dado. +1 de mi parte –

3

Esto resultó ser un hilo muy útil.

Para aquellos que son alérgicos a las llaves, aquí es la versión VB.NET de Lucas y respuestas de 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 
+0

Alérgico a las llaves. Hahaha :(Dios, mi jefe tiene una alocada reacción alérgica a ellos. –

1

Para añadir a todo el trabajo impresionante Empecé por Lucas Estoy publicar una más que toma un valor de clase css y trata clase y alt como parámetros opcionales (válido en ASP.NET 3.5+). Esto permitirá una mayor funcionalidad pero reducirá el número de métodos sobrecargados necesarios.

// 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); 
    } 
+0

Además, para cualquier persona nueva en MVC, consejo útil: el valor de routeValue shoudl be @ RouteTable.Routes ["Home"] o cualquiera que sea tu ID de "ruta" la RouteTable. –

1

modificación de diapositivas cambió ayudante

 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); 
    } 

Clase CSS

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

Crear el enlace sólo tiene que pasar el nombre de clase

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

me he unido a la respuesta de Lucas y "ASP.NET MVC Helpers, Merging two object htmlAttributes together" a nd además controllerName al siguiente código:

uso // Muestra en CSHTML

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

Y la clase de extensión para el código anterior:

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) 
     { 
      //https://stackoverflow.com/questions/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) 
     { 
      //https://stackoverflow.com/questions/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; 
     } 
    } 
} 
0

esto sería un trabajo muy fino

<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> 
Cuestiones relacionadas