2010-03-31 18 views
17

hoy me confundí al hacer un par de <%=Html.LabelFor(m=>m.MyProperty)%> en ASP.NET MVC 2 y usando el atributo [DisplayName("Show this instead of MyProperty")] de System.ComponentModel.preguntándose por qué el atributo DisplayName se ignora en LabelFor en una propiedad anulada

Al final resultó que, cuando puse el atributo en una propiedad anulada, LabelFor no pareció notarlo.
Sin embargo, el atributo [Required] funciona bien en la propiedad anulada, y el mensaje de error generado realmente usa DisplayNameAttribute.

Este es un ejemplo de código trivial, el escenario más realista es que tengo un modelo de base de datos separado del modelo de vista, pero por conveniencia, me gustaría heredar del modelo de base de datos, agregar propiedades de solo visualización y decorar el modelo de vista con el atributos para la interfaz de usuario.

public class POCOWithoutDataAnnotations 
{ 
    public virtual string PleaseOverrideMe { get; set; }   
} 
public class EditModel : POCOWithoutDataAnnotations 
{ 
    [Required] 
    [DisplayName("This should be as label for please override me!")] 
    public override string PleaseOverrideMe 
    { 
     get { return base.PleaseOverrideMe; } 
     set { base.PleaseOverrideMe = value; } 
    } 

    [Required] 
    [DisplayName("This property exists only in EditModel")] 
    public string NonOverriddenProp { get; set; } 
} 

El establecimiento inflexible ViewPage<EditModel> contiene:

 <div class="editor-label"> 
      <%= Html.LabelFor(model => model.PleaseOverrideMe) %> 
     </div> 
     <div class="editor-field"> 
      <%= Html.TextBoxFor(model => model.PleaseOverrideMe) %> 
      <%= Html.ValidationMessageFor(model => model.PleaseOverrideMe) %> 
     </div> 

     <div class="editor-label"> 
      <%= Html.LabelFor(model => model.NonOverriddenProp) %> 
     </div> 
     <div class="editor-field"> 
      <%= Html.TextBoxFor(model => model.NonOverriddenProp) %> 
      <%= Html.ValidationMessageFor(model => model.NonOverriddenProp) %> 
     </div> 

Las etiquetas se muestran entonces como "PleaseOverrideMe" (no utilizando el DisplayNameAttribute) y "esta propiedad existe sólo en EditModel" (utilizando DisplayNameAttribute) al visualizar la página.
Si publico con valores vacíos, lo que provocó la validación con este ActionMethod:

[HttpPost] 
    public ActionResult Edit(EditModel model) 
    { 
     if (!ModelState.IsValid) 
      return View(model); 
     return View("Thanks"); 
    } 

la <%= Html.ValidationMessageFor(model => model.PleaseOverrideMe) %> realidad utiliza [DisplayName("This should be as label for please override me!")] atributo, y produce el defecto ErrorText "The Esta debe ser tan etiqueta para por favor me anular campo es! necesario."

¿Algún alma amistosa arrojará algo de luz sobre esto?

+0

Lasse, ¿ha tenido un poco de suerte en el ínterin? –

+0

Si está utilizando el reflejo para mostrar todas sus propiedades, tiene el tipo 'ModelMetadata' disponible para usted. Básicamente, harías esto 'Html.Label (prop.GetDisplayName())'. –

Respuesta

11

Model binding and metadata using the strongly-typed helpers looks at the declared, rather than the runtime, type of the model. Considero que esto es un error, pero aparentemente el equipo de MVC no está de acuerdo conmigo, ya que mi problema de Connect en este tema se cerró como "Por diseño".

+4

Bueno, intentaré archivarlo como un error @ Connect y estar preparado para "By Design". Gracias! –

+0

¿No es un error? Moví todo mi proyecto a MVC 3 y esto es un dolor de mi parte. Solía ​​funcionar bien, ¿no se supone que el atributo DisplayName funciona de esta manera ahora? – Jack

+0

Entonces, ¿qué sucede cuando anulas la plantilla de editar/mostrar objetos y usas 'Html.EditorForModel'? Dentro de su plantilla utiliza 'Html.Label()' y no puede obtener el atributo Mostrar. ¿Por diseño? ¿Contrataron imbéciles del equipo de IE? –

2

Tuve el mismo problema cuando tenía una vista parcial fuertemente tipada a una interfaz. La interfaz definió un DisplayName y la clase que implementó la interfaz intentó anularla. La única forma que encontré para que respetara la anulación fue escribir en la clase de implementación. Tuve que cambiar el tipo de modelo o el molde de la vista. Desafortunadamente, eso niega completamente los beneficios de usar la interfaz como el tipo de modelo. Estoy adivinando que terminaré con un cierto nivel de marcado de vista duplicado para cada clase de implementación, mientras que no incluyo dentro de los "ayudantes" fuertemente tipados.

En la remota posibilidad de que este tipo de solución sea remotamente útil (no estoy ilusionándome), aquí hay un ejemplo. Ciertamente hay formas de trabajar en esto para todas las posibles clases de implementación que intentan anular un nombre, pero definitivamente es más complicado de lo que debería ser.

public interface IAddressModel { 
    ... 
    [DisplayName("Province")] 
    public string Province { get; set; } 
    ... 
} 
public class UsAddressModel : IAddressModel { 
    ... 
    [DisplayName("State")] 
    public string Province { get; set; } 
    ... 
} 

<%= Html.LabelFor(m => m.State) %> <!--"Province"--> 
<%= Html.LabelFor(m => (m as UsAddressModel).State) %> <!--"State"--> 
11

me encontré con este problema utilizando [DisplayName ("Nombre de perfil")] y en su lugar utiliza [Display(Name = "Profile Name")] que fijó el problema en mi caso. No estoy seguro si esto sería útil.

La primera es de System.ComponentModel mientras que la segunda es de System.ComponentModel.DataAnnotations.

+3

Seis años después, esto solucionó el mismo problema en MVC 5 :) – pmbanka

+1

+ siete. Corregido en core mvc * thumb up * –

3

Ok, parece que encontré una solución si no usa la etiqueta requerida con ella. solo use un atributo de longitud o expresión regular para determinar si hay una entrada válida. Espero que esto ayude, aunque es un poco tarde.

[RegularExpression(@"^[1-9][0-9][0-9]$")] //validates that there is at least 1 in the quantity and no more than 999 
[DisplayName("Quantity:")] 
public string quantity { get; set; } 

Still works.

3

En mi caso se me olvidó convertirlo en una propiedad mediante el uso de getters y setters. En lugar de

public string CompanyName; 

Debería haber usado

public string CompanyName {get;set;} 
Cuestiones relacionadas