asp.net-mvc - tutorial - viewmodel asp net mvc 4
ViewModel con List<BaseClass> y plantillas de editor (2)
Hubo "Carpeta de modelo de tipo derivado" en mvccontrib. Pero, desafortunadamente, no existe una carpeta de este tipo en mvccontrib versión 3
Tengo una vista que enumera tablas que se agregan a un plano de planta. Las tablas se derivan de TableInputModel
para permitir RectangleTableInputModel
, CircleTableInputModel
, etc.
ViewModel tiene una lista de TableInputModel
que son todos uno de los tipos derivados.
Tengo una vista parcial para cada uno de los tipos derivados y, dada una List
de tipos derivados mixtos, el marco sabe cómo representarlos.
Sin embargo, al enviar el formulario, la información del tipo se pierde. Lo he intentado con una carpeta de modelo personalizada, pero como la información de tipo se pierde cuando se envía, no funcionará ...
¿Alguien ha intentado esto antes?
Suponiendo que tiene los siguientes modelos:
public abstract class TableInputModel
{
}
public class RectangleTableInputModel : TableInputModel
{
public string Foo { get; set; }
}
public class CircleTableInputModel : TableInputModel
{
public string Bar { get; set; }
}
Y el siguiente controlador:
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);
}
}
Ahora podrías escribir vistas.
Vista principal Index.cshtml
:
@model TableInputModel[]
@using (Html.BeginForm())
{
@Html.EditorForModel()
<input type="submit" value="OK" />
}
y las plantillas de editor correspondientes.
~/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)
y la última falta de paz del rompecabezas es la carpeta de modelo personalizado para el tipo TableInputModel
que utilizará el valor de campo oculto publicado para buscar el tipo y crear una instancia de la implementación adecuada:
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;
}
}
que se registrará en Application_Start
:
ModelBinders.Binders.Add(typeof(TableInputModel), new TableInputModelBinder());
y eso es más o menos todo. Ahora, dentro de la acción Publicar índice, la matriz modelo se inicializará correctamente con los tipos correctos.