Если у вас есть следующие модели:
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
, который будет использовать значение скрытого поля для извлечения типа и создания экземпляра правильной реализации:
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 массив моделей будет правильно инициализирован с правильными типами.