Интересно, почему атрибут DisplayName игнорируется в LabelFor при переопределенном свойстве

Сегодня я запутался, когда делал пару <%=Html.LabelFor(m=>m.MyProperty)%> в ASP.NET MVC 2 и использовал атрибут [DisplayName("Show this instead of MyProperty")] из System.ComponentModel.

Как оказалось, когда я помещал атрибут в переопределенное свойство, LabelFor, похоже, не заметил его.
Однако атрибут [Required] отлично работает в переопределенном свойстве, и сгенерированный errormessage фактически использует DisplayNameAttribute.

Это какой-то тривиальный пример кода, более реалистичным сценарием является то, что у меня есть база данных данных отдельно от модели viewmodel, но для удобства я хотел бы наследовать из базы данных данных, добавлять свойства View-only и декорировать модель с атрибутами для пользовательского интерфейса.

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

Сильно типизированный ViewPage<EditModel> содержит:

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

Затем метки отображаются как "PleaseOverrideMe" ( не с использованием DisplayNameAttribute) и "Это свойство существует только в EditModel" ( с использованием DisplayNameAttribute) при просмотре страницы.
Если я отправляю пустые значения, запуская проверку с помощью этого ActionMethod:

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

<%= Html.ValidationMessageFor(model => model.PleaseOverrideMe) %> на самом деле использует атрибут [DisplayName("This should be as label for please override me!")] и создает по умолчанию errortext. "Это должно быть как метка для поля" пожалуйста, переопределите меня! ".

Может ли какая-нибудь дружеская душа пролить свет на это?

Ответы

Ответ 1

привязка модели и метаданные с использованием строго типизированных помощников рассматривает тип модели, объявленный, а не тип исполнения. Я считаю, что это ошибка, но, видимо, команда MVC не согласна со мной, так как моя проблема с Connect на этом была закрыта как "По дизайну".

Ответ 2

Я столкнулся с этой проблемой, используя [DisplayName ( "Имя профиля" )] и вместо этого использовал [Display(Name = "Profile Name")], который исправил проблему в моем случае. Я не уверен, что это было бы полезно.

Первый из System.ComponentModel, а последний из System.ComponentModel.DataAnnotations.

Ответ 3

Хорошо, я, похоже, нашел обходное решение, если вы не используете тег Required с ним! просто используйте атрибут регулярного выражения или длины, чтобы определить, существует ли допустимая запись. Надеюсь, это поможет, хотя и немного поздно.

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

Все еще работает.

Ответ 4

В моем случае я был забыт сделать его собственностью, используя геттеры и сеттеры. Вместо

public string CompanyName;

Я должен был использовать

public string CompanyName {get;set;}

Ответ 5

У меня была такая же проблема, когда у меня было частичное представление, строго типизированное для интерфейса. Интерфейс определил DisplayName, а класс, который реализовал интерфейс, попытался переопределить его. Единственный способ, который я нашел, чтобы заставить его уважать переопределение, - это ввести класс реализации. Мне пришлось либо изменить тип модели просмотра, либо бросить. К сожалению, это полностью отрицает преимущества использования интерфейса в качестве типа модели. Я предполагаю, что у меня будет некоторый уровень дублированной разметки разметки для каждого класса реализации, в то время как не выполняется в пределах строго типизированных "помощников".

В отдаленном случае, что этот способ обхода даже отдаленно полезен (не доставляя надежды), вот пример. Конечно, есть способы работать с этим для всех возможных классов реализации, которые пытаются переопределить имя, но это определенно больше хлопот, чем должно быть.

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