2012-05-11 25 views
5

esta es una pregunta de seguimiento de MVC3 Razor httppost return complex objects child collections.mvc3 razor editortemplate con clases abstractas

El ejemplo que di fue muy simple. La colección secundaria es en realidad una colección de objetos que provienen de una clase base abstracta. Entonces, la colección tiene una lista de clases base.

He creado una plantilla para cada clase derivada y he intentado usar if child de type y luego doy el nombre de la plantilla como una cadena. Las plantillas se muestran en la vista pero no se rellenan en la publicación posterior.

No estoy seguro de cómo uso el editor por bit con las plantillas para elegir la plantilla correcta y obtener la información que se recopilará en los objetos secundarios dentro del contenedor padre.

Respuesta

8

Puede usar un encuadernador de modelo personalizado. Tomemos un ejemplo.

Modelo:

public class MyViewModel 
{ 
    public IList<BaseClass> Children { get; set; } 
} 

public abstract class BaseClass 
{ 
    public int Id { get; set; } 

    [HiddenInput(DisplayValue = false)] 
    public string ModelType 
    { 
     get { return GetType().FullName; } 
    } 
} 

public class Derived1 : BaseClass 
{ 
    public string Derived1Property { get; set; } 
} 

public class Derived2 : BaseClass 
{ 
    public string Derived2Property { get; set; } 
} 

controlador:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     var model = new MyViewModel 
     { 
      Children = new BaseClass[] 
      { 
       new Derived1 { Id = 1, Derived1Property = "prop1" }, 
       new Derived2 { Id = 2, Derived2Property = "prop2" }, 
      } 
     }; 
     return View(model); 
    } 

    [HttpPost] 
    public ActionResult Index(MyViewModel model) 
    { 
     // everything will be fine and dandy here 
     ... 
    } 
} 

Ver (~/Views/Home/Index.cshtml): plantilla

@model MyViewModel 

@using (Html.BeginForm()) 
{ 
    for (int i = 0; i < Model.Children.Count; i++) 
    { 
     @Html.EditorFor(x => x.Children[i].ModelType) 
     <div> 
      @Html.EditorFor(x => x.Children[i].Id) 
      @Html.EditorFor(x => x.Children[i])  
     </div> 
    } 

    <button type="submit">OK</button> 
} 

Editor para el tipo Dervied1 (~/Views/Home/EditorTemplates/Derived1.cshtml):

@model Derived1 
@Html.EditorFor(x => x.Derived1Property) 

y el editor de plantillas para el tipo Dervied2 (~/Views/Home/EditorTemplates/Derived2.cshtml):

@model Derived2 
@Html.EditorFor(x => x.Derived2Property) 

Ahora todo lo que queda es un aglutinante modelo personalizado que va a utilizar el valor del campo oculto para crear una instancia del tipo adecuado en la colección:

public class BaseClassModelBinder : 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 en Application_Start:

ModelBinders.Binders.Add(typeof(BaseClass), new BaseClassModelBinder()); 
+0

increíble ... que funcionó bien ... Tuve que volver a trabajar y comprar la computadora portátil para probar esto ya que se veía genial ... hice mi fin de semana, incluso antes de que comenzara – Jon