2011-06-14 11 views
30

He creado un proyecto MVC 3 predeterminado (usando una afeitadora), para demostrar un problema.TextBoxFor vs EditorFor, y htmlAttributes vs additionalViewData

En la página de inicio de sesión, hay una línea:

@Html.TextBoxFor(m => m.UserName) 

si cambio esto:

@Html.TextBoxFor(m => m.UserName, new { title = "ABC" }) 

Entonces el que se representa como (con un atributo de título):

<input data-val="true" data-val-required="The User name field is required." id="UserName" name="UserName" title="ABC" type="text" value="" /> 

Sin embargo, si lo hago un editorPara:

@Html.EditorFor(m => m.UserName, new { title = "ABC" }) 

Entonces se rindió (sin atributo title) como:

<input class="text-box single-line" data-val="true" data-val-required="The User name field is required." id="UserName" name="UserName" type="text" value="" /> 

Así que en resumen, el atributo de título se pierde cuando uso EditorFor.

Sé que el segundo parámetro para TextBoxFor se llama htmlAttributes, y para EditorFor es additionalViewData, sin embargo, he visto ejemplos donde EditorFor puede representar atributos proporcionados con este parámetro.

¿Alguien puede explicar lo que estoy haciendo mal y cómo puedo tener un atributo de título cuando uso EditorFor?

+0

Fantástico, me iba a preguntar sobre este problema exacto. – aknuds1

Respuesta

5

Usted puede echar un vistazo a la following blog post que ilustra cómo implementar un proveedor de metadatos personalizados y utilizar las anotaciones de datos en el modelo de vista con el fin de definir las propiedades de HTML, como class, maxlength, title, ... Esto podría ser entonces utilizado junto con los ayudantes con plantilla.

+3

Aunque es impresionante, esa solución es el proverbial trineo para una nuez. ¿Hay una solución más sutil? –

+1

@ G-unit, no, no hay. EditorFor no admite pasar atributos html. No tendría sentido ya que ni siquiera sabes cómo se implementaría la plantilla. Podría ser una plantilla personalizada para la que los atributos html no tienen sentido. Entonces, la única forma de lograr esto sería escribir un proveedor de metadatos personalizado. Personalmente, eso es lo que uso y estoy muy contento con los resultados. –

+0

¡Gracias, me inclino por tu sabiduría! –

12

En MVC3 puede agregar un título (y otros atributos html) utilizando este tipo de solución si crea una plantilla personalizada de EditorFor. Este caso se prepara para el valor a ser opcional, editorFor no se requieren llamadas para incluir el object additionalViewData

@Html.EditorFor(m => m.UserName, "CustomTemplate", new { title = "ABC" }) 

EditorTemplates/CustomTemplate.cshtml

@{ 
    string s = ""; 
    if (ViewData["title"] != null) { 
     // The ViewData["name"] is the name of the property in the addtionalViewData... 
     s = ViewData["title"].ToString(); 
    } 
} 

@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { title = s }) 

hice algo muy similar para incluir una clase opcional en un EditorTemplate. Puede agregar tantos elementos a addtionalViewData como desee, pero necesita manejar cada uno en la plantilla EditorFor.

14

Creo que encontré una solución más agradable. EditorFor toma adicionalViewData como parámetro. Si usted le da un parámetro denominado "htmlAttributes" con los atributos, entonces podemos hacer cosas interesantes con ella:

@Html.EditorFor(model => model.EmailAddress, 
       new { htmlAttributes = new { @class = "span4", 
              maxlength = 128, 
              required = true, 
              placeholder = "Email Address", 
              title = "A valid email address is required (i.e. [email protected])" } }) 

En la plantilla (en este caso, EmailAddress.cshtml) a continuación, puede proporcionar unos atributos predeterminados:

@Html.TextBox("", 
       ViewData.TemplateInfo.FormattedModelValue, 
       Html.MergeHtmlAttributes(new { type = "email" })) 

La magia se une a través de este método de ayuda:

public static IDictionary<string, object> MergeHtmlAttributes<TModel>(this HtmlHelper<TModel> htmlHelper, object htmlAttributes) 
{ 
    var attributes = htmlHelper.ViewData.ContainsKey("htmlAttributes") 
          ? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlHelper.ViewData["htmlAttributes"]) 
          : new RouteValueDictionary(); 

    if (htmlAttributes != null) 
    { 
     foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(htmlAttributes)) 
     { 
      var key = property.Name.Replace('_', '-'); 
      if (!attributes.ContainsKey(key)) 
      { 
       attributes.Add(key, property.GetValue(htmlAttributes)); 
      } 
     } 
    } 

    return attributes; 
} 

supuesto, usted podría modificarlo para hacer que los atributos, así que si usted está haciendo HTML sin procesar:

public static MvcHtmlString RenderHtmlAttributes<TModel>(this HtmlHelper<TModel> htmlHelper, object htmlAttributes) 
{ 
    var attributes = htmlHelper.ViewData.ContainsKey("htmlAttributes") 
          ? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlHelper.ViewData["htmlAttributes"]) 
          : new RouteValueDictionary(); 

    if (htmlAttributes != null) 
    { 
     foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(htmlAttributes)) 
     { 
      var key = property.Name.Replace('_', '-'); 
      if (!attributes.ContainsKey(key)) 
      { 
       attributes.Add(key, property.GetValue(htmlAttributes)); 
      } 
     } 
    } 

    return MvcHtmlString.Create(String.Join(" ", 
     attributes.Keys.Select(key => 
      String.Format("{0}=\"{1}\"", key, htmlHelper.Encode(attributes[key]))))); 
} 
+0

¿Sería tan amable de proporcionar un proyecto de muestra completo que utilizara el código? publicaste? Soy nuevo en ASP.NET y en la pérdida de dónde colocar las clases 'MergeHtmlAttributes' y' RenderHtmlAttributes'. –

+1

@RosdiKasim: estos son métodos de extensión que normalmente almaceno en una clase estática que refleja el espacio de nombres del conjunto común de ayudantes HTML o un nuevo espacio de nombres que incluyo en el archivo web.config en la carpeta Vistas para no tener que siga haciendo referencia a él en cada página. Así que básicamente "HtmlHelperExtensions.cs" en la raíz del proyecto o una carpeta de Infraestructura. –

+0

Ok, gracias. Voy a darle una oportunidad. –

Cuestiones relacionadas