2010-03-31 7 views
17

oggi mi sono confuso quando eseguo un paio di <%=Html.LabelFor(m=>m.MyProperty)%> in ASP.NET MVC 2 e utilizzando l'attributo [DisplayName("Show this instead of MyProperty")] da System.ComponentModel.Si chiede perché l'attributo DisplayName viene ignorato in LabelFor su una proprietà sostituita

Come si è scoperto, quando ho messo l'attributo su una proprietà sovrascritta, LabelFor non sembra averlo notato.
Tuttavia, l'attributo [Required] funziona correttamente sulla proprietà sottoposta a override e il messaggio generato generico utilizza effettivamente DisplayNameAttribute.

Questo è un po 'examplecode banale, lo scenario più realistico è che ho un databasemodel separato dal ViewModel, ma per comodità, mi piacerebbe ereditare dalla databasemodel, aggiungere solo visualizzazione proprietà e decorare il ViewModel con la attributi per l'interfaccia utente.

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

Il fortemente tipizzato 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> 

Le etichette vengono quindi visualizzati come "PleaseOverrideMe" (non utilizzando il DisplayNameAttribute) e "Questa struttura esiste solo in EditModel" (utilizzando DisplayNameAttribute) durante la visualizzazione della pagina.
Se pubblico con valori vuoti, innescando la convalida con questo ActionMethod:

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

il <%= Html.ValidationMessageFor(model => model.PleaseOverrideMe) %> utilizza effettivamente [DisplayName("This should be as label for please override me!")] attributo, e produce il default ErrorText "The Questa dovrebbe essere come etichetta per favore mi ignorare campo è! necessario."

Qualche anima amica farebbe luce su questo?

+0

Lasse, hai avuto fortuna nel frattempo? –

+0

Se si utilizza la riflessione per visualizzare tutte le proprietà, è disponibile il tipo 'ModelMetadata'. Essenzialmente si farebbe questo 'Html.Label (prop.GetDisplayName())'. –

risposta

11

Model binding and metadata using the strongly-typed helpers looks at the declared, rather than the runtime, type of the model. Lo considero un bug, ma a quanto pare il team MVC non è d'accordo con me, poiché il mio problema su Connect è stato chiuso come "By Design".

+4

Bene, proverò a archiviarlo come un bug @ Connetti e poi preparati per "By Design". Grazie! –

+0

Non è un bug? Ho spostato il mio intero progetto su MVC 3 e questo è un dolore al mio fianco. Funzionava benissimo - l'attributo DisplayName non dovrebbe funzionare in questo modo ora? – Jack

+0

Quindi cosa succede quando si sostituisce il modello di modifica/visualizzazione dell'oggetto e si usa 'Html.EditorForModel'? All'interno del tuo template usi 'Html.Label()' e non puoi ottenere l'attributo Display. Dal design? Hanno assunto idioti dal team di IE ?. –

2

Ho avuto lo stesso problema quando avevo una vista parziale fortemente digitata su un'interfaccia. L'interfaccia ha definito un DisplayName e la classe che ha implementato l'interfaccia ha provato a sovrascriverlo. L'unico modo che ho trovato per ottenere il rispetto dell'override era digitare sulla classe di implementazione. Ho dovuto modificare il tipo di modello o il cast della vista. Sfortunatamente, ciò vanifica completamente i vantaggi dell'uso dell'interfaccia come tipo di modello. Sto indovinando che finirò con un certo livello di markup di visualizzazione duplicato per ogni classe di implementazione mentre non getterò all'interno degli "helper" fortemente tipizzati.

Nella remota eventualità che questo tipo di soluzione alternativa sia addirittura utile da un punto di vista remoto (non mi sto illudendo), ecco un esempio. Ci sono certamente modi di lavorare in questo modo per tutte le possibili classi di implementazione che cercano di sovrascrivere un nome, ma è decisamente più fastidioso di quanto dovrebbe essere.

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

mi sono imbattuto in questo problema utilizzando [DisplayName ("Nome profilo")] e invece utilizzato [Display(Name = "Profile Name")] che ha risolto il problema nel mio caso. Non sono sicuro se questo sarebbe utile.

Il primo è da System.ComponentModel mentre il secondo è da System.ComponentModel.DataAnnotations.

+3

Sei anni più tardi, questo risolve lo stesso problema in MVC 5 :) – pmbanka

+1

+ sette. Risolto nel core mvc * thumb up * –

3

Ok, mi sembra di aver trovato una soluzione alternativa se non si utilizza il tag Richiesto con esso! basta usare un'espressione regolare o l'attributo length per determinare se c'è una voce valida. Spero che questo aiuti, anche se è un po 'tardi.

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

Lavori in corso.

3

Nel mio caso sono stato dimenticato di farne una proprietà utilizzando getter e setter. Invece di

public string CompanyName; 

avrei dovuto usare

public string CompanyName {get;set;} 
Problemi correlati