ASP.NET MVC — передать внешнюю модель в шаблон редактора

Я использую пользовательские шаблоны редактора для большинства своих форм, но, пытаясь использовать их для отображения пользовательского средства выбора объектов, я не нашел простого способа передать информацию о содержащемся контексте в шаблон редактора.

В частности, моя основная форма отображает редактирование для объекта домена, а шаблон редактора должен отображать средство выбора AJAX, которое содержит список объектов, зависящих от идентификатора объекта домена. В настоящее время я передаю идентификатор, используя параметр additionalViewData, который, как мне кажется, подвержен ошибкам и поэтому довольно уродлив.

Моя форма содержит код, подобный следующему:

@Html.EditorFor(model => model.CategoryId, new { id = model.id })

Шаблон редактора содержит следующий код:

@{
var domainObjectId = ViewData["id"] as int?;
}

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

Итак, мои вопросы:

  1. Можно ли использовать ModelMetadataProvider для передачи информации о содержащейся модели в шаблон редактора?
  2. Если нет, есть ли более аккуратный/простой способ добиться того, что я пытаюсь, помимо передачи каждой части дополнительной информации через слабо типизированный параметр additionalViewData?

Заранее спасибо!


person Ian Newson    schedule 16.04.2013    source источник


Ответы (2)


Вы должны понимать, что EditorTemplates предназначены для конкретного типа, а не контекста. Некоторое внимание было уделено этому параметру AdditionalViewData, но это лучшее, что вы можете получить.

Если вы беспокоитесь о безопасности типов, используйте вместо этого ViewBag, который представляет собой динамическую оболочку для ViewData, безопасную для типов.

@{
    var domainObjectId = ViewBag.Id;
}
person Erik Funkenbusch    schedule 17.04.2013
comment
Спасибо за Ваш ответ. К сожалению, я думаю, что вы правы в том, что это был выбор дизайна, но они были бы просто более полезными, если бы они были контекстно-зависимыми. Я принимаю ваш ответ, но я думаю, что я собираюсь использовать обычный частичный шаблон вместо шаблонов редактора для этих конкретных полей, а не ViewBag или аналогичный. - person Ian Newson; 17.04.2013
comment
@IanNewson - я не понимаю вашего нежелания использовать ViewBag, поскольку он действительно предназначен для этого. Я называю это мышлением верстки стола. Люди узнают, что использование html-таблиц для макета — это плохо, поэтому они перестают использовать таблицы для всего, даже для фактических табличных данных (вы видите таблицы, состоящие из div). Точно так же люди узнают, что вы должны использовать ViewModels, а не ViewData/Bag, и держаться подальше, даже если они используются для того, для чего они предназначены. - person Erik Funkenbusch; 17.04.2013
comment
@IanNewson - Кстати, если вы собираетесь использовать партиал, вам придется уделить особое внимание именованию элемента управления формой, чтобы убедиться, что вложенные объекты учтены. EditorTemplates в основном позаботится об этом за вас. Честно говоря, я не большой поклонник использования EditorTemplates для выпадающих списков. Я также думаю, что с этим лучше было бы справиться во внешнем файле javascript и вместо этого использовать атрибут данных. - person Erik Funkenbusch; 17.04.2013
comment
В целом я не против использования ViewBag, хотя по двум причинам это не лучший выбор в данной ситуации; 1) Я создаю повторно используемый компонент, несколько из которых могут находиться на одной странице, и каждый из них может быть привязан к разным объектам предметной области. 2) Я создаю структуру для других разработчиков, и я думаю, что явная строго типизированная в этом случае желателен метод частичного + расширения. - person Ian Newson; 18.04.2013
comment
Об уникальности id уже позаботились. Я не понимаю, почему вы говорите, что было бы лучше использовать внешний файл JS + раскрывающийся список, поскольку я не думаю, что упомянул какие-либо детали реализации? Мой вопрос касался исключительно передачи необходимой информации в представление, которое в ней нуждается, а не того, что делается с этой информацией в представлении. - person Ian Newson; 18.04.2013
comment
@IanNewson - Почему вы постоянно упоминаете строго типизированный текст? ViewBag является строго типизированным. Но на самом деле вы упомянули реализацию, вы сказали, что это раскрывающийся список, заполненный вызовом Ajax, то есть javascript. Не должно быть никаких причин, по которым вашему раскрывающемуся списку нужно знать какие-либо конкретные идентификаторы. Похоже, вы занимаетесь бизнес-логикой, на ваш взгляд, и это нарушение принципа разделения интересов. Если вам нужно заполнить раскрывающийся список из вызова ajax, вы просто помещаете нужный идентификатор в атрибут данных раскрывающегося списка и имеете внешнюю функцию javascript, которая считывает атрибут - person Erik Funkenbusch; 18.04.2013
comment
@IanNewson - И я не говорил об уникальности идентификатора. Я говорю о том, чтобы убедиться, что поля формы названы правильно, чтобы средство связывания модели могло правильно связать их контекст, когда они вложены в другие модели представления. Дело не только в том, чтобы убедиться, что они уникальны, они должны соответствовать формату вязальной проволоки модели. - person Erik Funkenbusch; 18.04.2013
comment
Я сбит с толку тем, как эта ветка развивалась таким образом, но достаточно сказать, что теперь я доволен своим подходом. Спасибо за вашу помощь! - person Ian Newson; 18.04.2013

Интересно, может быть, контроллер, который создает эту модель представления, должен быть тем, что выбирает список объектов. Таким образом, вместо того, чтобы иметь целочисленное свойство в вашей модели представления, вы можете иметь подсвойство другого типа модели представления, то есть:

public class OuterViewModel
{
    public CategoryViewModel Category { get; set; }
}

public class CategoryViewModel
{
    public int CategoryId { get; set; }

    public IEnumerable<SelectListItem> ListOfThings { get; set; }
}

Тогда ваш исходный вид может просто иметь:

@Html.EditorFor(model => model.Category)

С EditorTemplate для CategoryViewModel, который выглядит так:

@model CategoryViewModel
@Html.DropDownFor(m => m.CategoryId, Model.ListOfThings)

Единственное, что вы должны помнить, это то, что если вы выполняете какую-либо проверку бизнес-логики на стороне сервера, добавляете ошибки модели и возвращаетесь к своему представлению, вам нужно будет повторно заполнить свой список вещей в вашем действии публикации контроллера.

person Ian Routledge    schedule 17.04.2013
comment
Спасибо за Ваш ответ. Для обычного select или подобного я бы с вами согласился, но в этом случае виджет пользовательского интерфейса представляет собой настраиваемое средство выбора, заполняемое с помощью вызова AJAX, и включает в себя поиск и пейджинг. Поэтому мне нужно передать всю информацию, необходимую для создания серверной части списка во время вызова AJAX. Это включает в себя идентификатор объекта, а также несколько других переменных, и это информация, которую мне нужно передать в шаблон. - person Ian Newson; 17.04.2013
comment
Хорошо замените IEnumerable на int, который является идентификатором внешней модели, и вместо того, чтобы отображать раскрывающийся список, визуализируйте то, что вы хотите? - person Ian Routledge; 17.04.2013