2010-03-31 5 views
17

dziś wprawiłam się w zakłopotanie, robiąc kilka <%=Html.LabelFor(m=>m.MyProperty)%> w ASP.NET MVC 2 i używając atrybutu [DisplayName("Show this instead of MyProperty")] z System.ComponentModel.Zastanawiasz się, dlaczego atrybut DisplayName jest ignorowany w LabelFor na nadpisanej właściwości

Jak się okazało, kiedy umieściłem atrybut na przesłoniętej właściwości, LabelFor najwyraźniej go nie zauważył.
Jednak atrybut [Required] działa poprawnie na przesłanianej właściwości, a wygenerowany błąd automatycznie używa DisplayNameAttribute.

To jest trywialny kod przykładowy, bardziej realistycznym scenariuszem jest to, że mam model bazy danych oddzielony od viewmodelu, ale dla wygody chciałbym dziedziczyć z modelu bazy danych, dodawać właściwości tylko do widoku i dekorować model widoku za pomocą atrybuty interfejsu użytkownika.

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

silnie typami ViewPage<EditModel> zawiera:

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

Etykiety są wtedy wyświetlane jako "PleaseOverrideMe" (nie używając DisplayNameAttribute) i "Ta właściwość istnieje tylko w EditModel" (przy użyciu the DisplayNameAttribute) podczas przeglądania strony.
Gdybym rozpoczynać z pustych wartości, wyzwalanie walidacji z tym ActionMethod:

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

<%= Html.ValidationMessageFor(model => model.PleaseOverrideMe) %> faktycznie używa [DisplayName("This should be as label for please override me!")] atrybut i tworzy domyślny errortext „The ta powinna być jak etykieta na prosimy przesłonić mi pole jest! wymagany."

Czy jakaś przyjazna dusza rzuci trochę światła na to?

+0

Lasse, miałeś szczęścia w międzyczasie? –

+0

Jeśli używasz refleksji do wyświetlania wszystkich twoich właściwości, masz dostęp do typu 'ModelMetadata'. Zasadniczo zrobiłbyś to 'Html.Label (prop.GetDisplayName())'. –

Odpowiedz

11

Model binding and metadata using the strongly-typed helpers looks at the declared, rather than the runtime, type of the model. Uważam, że jest to błąd, ale najwyraźniej zespół MVC nie zgadza się ze mną, ponieważ mój problem z Connectem został zamknięty jako "wg projektu".

+4

Cóż, spróbuję zgłosić to jako błąd @ Connect i być przygotowanym na "według projektu". Dzięki! –

+0

Nie błąd? Przeniosłem cały mój projekt do MVC 3 i to jest ból z mojej strony. Kiedyś działało dobrze - czy atrybut DisplayName nie powinien teraz działać w ten sposób? – Jack

+0

Co się dzieje, gdy przesłonisz szablon obiektu edycji/ekranu i użyjesz 'Html.EditorForModel'? W twoim szablonie używasz 'Html.Label()' i nie możesz uzyskać atrybutu Display. Przez projekt? Czy zatrudnili kretynów z zespołu IE ?. –

2

Miałem ten sam problem, gdy miałem częściowy widok mocno wpisany do interfejsu. Interfejs zdefiniował DisplayName i klasa, która zaimplementowała interfejs, próbowała go przesłonić. Jedynym sposobem, w jaki znalazłem to, by uszanować nadpisanie, było wpisanie klasy wykonawczej. Musiałem zmienić typ modelu widoku lub rzutować. Niestety, to całkowicie neguje korzyści wynikające z używania interfejsu jako typu modelu. Zgaduję, że skończę z pewnym poziomem zduplikowanego znacznika widoku dla każdej klasy implementacji, a jednocześnie nie będę rzucał wewnątrz mocno napisanych "pomocników".

W tej małej szansie, że tego rodzaju obejście jest nawet zdalnie pomocne (nie mam nadziei), oto przykład. Z pewnością istnieją sposoby pracy z tymi wszystkimi możliwymi klasami implementacyjnymi, które starają się zastąpić nazwę, ale jest to zdecydowanie więcej kłopotu, niż powinno być.

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

wpadłem na ten problem przy użyciu [DisplayName ("nazwa profilu")] i zamiast stosować [Display(Name = "Profile Name")] które stały problem w moim przypadku. Nie jestem pewien, czy byłoby to przydatne.

Pierwszy z nich to System.ComponentModel, natomiast drugi z System.ComponentModel.DataAnnotations.

+3

Sześć lat później naprawiono ten sam problem w MVC 5 :) – pmbanka

+1

+ siedem. Naprawiono w rdzeniu mvc * kciuk w górę * –

3

Ok, wydaje się, że znalazłem obejście, jeśli nie użyłeś przy tym wymaganego tagu! po prostu użyj wyrażenia regularnego lub atrybutu length, aby określić, czy istnieje poprawny wpis. Mam nadzieję, że to pomaga, chociaż jest trochę późno.

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

Nadal działa.

3

W moim przypadku zapomniałem uczynić go właściwością przy użyciu modułów pobierających i ustawiających. Zamiast

public string CompanyName; 

powinny Użyłem

public string CompanyName {get;set;} 
Powiązane problemy