ViewModel со списком<BaseClass> и шаблонами редактора
У меня есть представление, в котором перечислены таблицы, добавляемые в план этажа. Таблицы происходят из TableInputModel
чтобы разрешить RectangleTableInputModel
, CircleTableInputModel
, так далее
ViewModel имеет список TableInputModel
которые все являются одним из производных типов.
У меня есть частичное представление для каждого из производных типов и дано List
из смешанных производных типов фреймворк знает, как их отобразить.
Однако при отправке формы информация о типе теряется. Я пробовал с пользовательским механизмом связывания модели, но поскольку информация о типе теряется при отправке, она не будет работать...
Кто-нибудь пробовал это раньше?
2 ответа
Предполагая, что у вас есть следующие модели:
public abstract class TableInputModel
{
}
public class RectangleTableInputModel : TableInputModel
{
public string Foo { get; set; }
}
public class CircleTableInputModel : TableInputModel
{
public string Bar { get; set; }
}
И следующий контроллер:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new TableInputModel[]
{
new RectangleTableInputModel(),
new CircleTableInputModel()
};
return View(model);
}
[HttpPost]
public ActionResult Index(TableInputModel[] model)
{
return View(model);
}
}
Теперь вы можете писать мнения.
Главный вид Index.cshtml
:
@model TableInputModel[]
@using (Html.BeginForm())
{
@Html.EditorForModel()
<input type="submit" value="OK" />
}
и соответствующие шаблоны редактора.
~/Views/Home/EditorTemplates/RectangleTableInputModel.cshtml
:
@model RectangleTableInputModel
<h3>Rectangle</h3>
@Html.Hidden("ModelType", Model.GetType())
@Html.EditorFor(x => x.Foo)
~/Views/Home/EditorTemplates/CircleTableInputModel.cshtml
:
@model CircleTableInputModel
<h3>Circle</h3>
@Html.Hidden("ModelType", Model.GetType())
@Html.EditorFor(x => x.Bar)
и последний отсутствующий мир головоломки - это пользовательское связующее для модели TableInputModel
type, который будет использовать опубликованное скрытое значение поля для извлечения типа и создания правильной реализации:
public class TableInputModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var typeValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".ModelType");
var type = Type.GetType(
(string)typeValue.ConvertTo(typeof(string)),
true
);
var model = Activator.CreateInstance(type);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type);
return model;
}
}
который будет зарегистрирован в Application_Start
:
ModelBinders.Binders.Add(typeof(TableInputModel), new TableInputModelBinder());
и это почти все. Теперь внутри действия Index Post массив моделей будет правильно инициализирован с правильными типами.
В mvccontrib была " Связывающая модель производного типа". Но, к сожалению, в mvccontrib версии 3 такого связующего нет