2012-05-11 19 views
5

questa è una domanda di follow-up da MVC3 Razor httppost return complex objects child collections.mvc3 rasoio editorelo con classi astratte

L'esempio che ho dato è stato molto semplice. La collezione figlio è in realtà una raccolta di oggetti che provengono tutti da una classe base astratta. Quindi la collezione ha una lista di classi base.

Ho creato un modello per ogni classe derivata e ho provato a utilizzare se child è di tipo, quindi fornire il nome del modello come stringa. I modelli sono renderizzati alla vista ma non inseriti nel post.

Non sono sicuro di come uso il bit di editorfor con i modelli per scegliere il modello corretto e ottenere il marshalling delle informazioni negli oggetti figlio all'interno del contenitore padre.

risposta

8

È possibile utilizzare un raccoglitore modello personalizzato. Facciamo un esempio.

Modello:

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; } 
} 

Controller:

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 
     ... 
    } 
} 

View (~/Views/Home/Index.cshtml): Modello

@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 per il tipo di Dervied1 (~/Views/Home/EditorTemplates/Derived1.cshtml):

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

e l'editor di modelli per il tipo di Dervied2 (~/Views/Home/EditorTemplates/Derived2.cshtml):

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

Ora tutto quello che resta è un modello personalizzato legante che utilizzerà il valore del campo nascosto per istanziare il tipo corretto della collezione:

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; 
    } 
} 

che sarà registrato in Application_Start:

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

fantastico ... che ha funzionato a meraviglia ... dovevo tornare al lavoro e prendere il portatile per provare questo dato che sembrava fantastico ... ha reso il mio weekend, prima ancora che iniziasse – Jon