ViewModel com lista e modelos de editor

Eu tenho uma visão que lista tabelas sendo adicionadas a uma planta baixa. Tabelas derivam de TableInputModel para permitir RectangleTableInputModel , CircleTableInputModel , etc

O ViewModel tem uma lista de TableInputModel que são todos um dos tipos derivados.

Eu tenho uma visão parcial para cada um dos tipos derivados e dada uma List de tipos derivados mistos que o framework sabe como renderizá-los.

No entanto, ao enviar o formulário, as informações de tipo são perdidas. Eu tentei com um fichário de modelo personalizado, mas porque o tipo de informação é perdido quando está sendo enviado, não vai funcionar …

Alguém já tentou isso antes?

Supondo que você tenha os seguintes modelos:

 public abstract class TableInputModel { } public class RectangleTableInputModel : TableInputModel { public string Foo { get; set; } } public class CircleTableInputModel : TableInputModel { public string Bar { get; set; } } 

E o seguinte 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); } } 

Agora você poderia escrever views.

Vista principal Index.cshtml :

 @model TableInputModel[] @using (Html.BeginForm()) { @Html.EditorForModel()  } 

e os modelos de editor correspondentes.

~/Views/Home/EditorTemplates/RectangleTableInputModel.cshtml :

 @model RectangleTableInputModel 

Rectangle

@Html.Hidden("ModelType", Model.GetType()) @Html.EditorFor(x => x.Foo)

~/Views/Home/EditorTemplates/CircleTableInputModel.cshtml :

 @model CircleTableInputModel 

Circle

@Html.Hidden("ModelType", Model.GetType()) @Html.EditorFor(x => x.Bar)

e a falta final do quebra-cabeça é o fichário de modelo personalizado para o tipo TableInputModel que usará o valor do campo oculto postado para buscar o tipo e instanciar a implementação adequada:

 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 será registrado no Application_Start :

 ModelBinders.Binders.Add(typeof(TableInputModel), new TableInputModelBinder()); 

e isso é praticamente tudo. Agora, dentro da ação Index Post, a matriz do modelo será inicializada corretamente com os tipos corretos.

Havia “Binder Model Model Derived” em mvccontrib. Mas, infelizmente, não existe tal fichário na versão 3 do mvccontrib