Использование интерфейса в качестве типа модели частичного представления + аннотации данных - PullRequest
8 голосов
/ 28 марта 2012

У меня есть случай, когда сложное частичное представление требует различной проверки полей в зависимости от того, где используется частичное представление.

Я подумал, что смогу обойти это, сделав частичное представление в качестве типа модели, используя интерфейс, и реализовав две разные модели представления на основе интерфейса. Аннотации данных в двух моделях представления будут разными. Затем я бы поставил экземпляр правильного ViewModel для частичного представления.

Но я обнаружил, что единственными аннотациями, которые распознаются, являются аннотации на самом интерфейсе. DA в классах ViewModel, реализующих интерфейс, игнорируются, даже если это объекты, которые передаются в качестве моделей. Так что мой план не работает.

Есть ли способ обойти это? Лучший подход? Я бы предпочел не разбивать частичное представление на отдельные представления, если я могу избежать этого.

ETA: это сокращенная версия частичного представления, согласно запросу:

@model IPerson
@Html.ValidationSummary(false)
<fieldset>
    <table class="editForm">
        <tr>
            <td class="editor-label">
                @Html.LabelFor(model => model.FirstName)
            </td>
            <td class="editor-field">
                @Html.EditorFor(model => model.FirstName)
                @Html.ValidationMessageFor(model => model.FirstName)
            </td>
            <td class="editor-label">
                @Html.LabelFor(model => model.LastName)
            </td>
            <td class="editor-field">
                @Html.EditorFor(model => model.LastName)
                @Html.ValidationMessageFor(model => model.LastName)
            </td>
        </tr>
     </table>
  <fieldset>

Реальное частичное представление довольно длинное и содержит множество операторов @if, управляющих рендерингом (или нет) необязательных секций, но он не делает ничего сложного.

Ответы [ 3 ]

3 голосов
/ 28 марта 2012

Моя идея не сработает: этот поток напомнил мне, что классы не наследуют атрибуты от своих интерфейсов.(Как указано в ответе, что произойдет, если два интерфейса задают одно и то же свойство с разными атрибутами, и оба были реализованы одним классом?)

Может работать с общим базовым классом.Я попробую это завтра.

Спасибо всем.

2 голосов
/ 28 марта 2012

Энн, ты права.Я удалил свой комментарий.Вы не можете опубликовать интерфейс обратно через ваш вид.Однако я не знаю, что именно вы пытаетесь сделать, так как не вижу ваш код.Может как то так?Я передаю интерфейс представлению, но передаю его обратно как ожидаемый класс.Опять же, я не уверен, что приложение здесь.

Допустим, у вас есть такие классы :

[MetadataType(typeof(PersonMetaData))]
public class Customer : IPerson {
    public int ID { get; set; }
    public string Name { get; set; }
     [Display(Name = "Customer Name")]
    public string CustomerName { get; set; }
}

public class Agent : IPerson {
    public int ID { get; set; }
    public string Name { get; set; }
}

public partial class PersonMetaData : IPerson {
    [Required]
    public int ID { get; set; }

    [Required]
    [Display(Name="Full Name")]
    public string Name { get; set; }
}

public interface IPerson {
    int ID { get; set; }
    string Name { get; set; }
}

public interface IAgent {
    int AgentType { get; set; }
}

public interface ICustomer {
    int CustomerType { get; set; }
}

Ваш контроллер выглядит как :

    public ActionResult InterfaceView() {
        IPerson person = new Customer {
            ID = 1
        };
        return View(person);
    }

    [HttpPost]
    public ActionResult InterfaceView(Customer person) {
        if (ModelState.IsValid) {
            TempData["message"] = string.Format("You posted back Customer Name {0} with an ID of {1} for the name: {2}", person.CustomerName, person.ID, person.Name);
        }
        return View();
    }

И ваш взгляд выглядит следующим образом :

@model DataTablesExample.Controllers.Customer

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@if (@TempData["message"] != null) {
    <p>@TempData["message"]</p>
}

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>IPerson</legend>

        @Html.HiddenFor(model => model.ID)

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.CustomerName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.CustomerName)
            @Html.ValidationMessageFor(model => model.CustomerName)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}
1 голос
/ 05 марта 2013

Ну, на самом деле у вас есть очень разумная идея! и может быть заархивирован, если вы используете не универсальную версию методов HtmlHelper (например, "@ Html.Editor" вместо "@ Html.EditorFor"), потому что универсальные версии воссоздают ModelMetadata (я не знаю почему!) основаны на универсальном типе параметра и не используют ModelMetadata представления. Черт возьми, не правда ли?

Надеюсь, что это поможет.

...