Mvc3 razor editortemplate with abstract classes

this is the next question from MVC3 Razor httppost returns complex child collections of objects .

The example I gave was very simple. A detailed collection is a collection of objects, all of which belong to an abstract base class. Thus, the collection has a list of base classes.

I created a template for each derived class and tried to use if the child type is of type, then give the name of the template as a string. Templates are displayed in the view but not populated in the message.

I am not sure how to use the editor for bits with templates to select the correct template and get the information that will be redirected back to child objects in the parent container.

+5
source share
1 answer

You can use a custom binder. Take an example.

Model:

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):

@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 template for type Dervied1( ~/Views/Home/EditorTemplates/Derived1.cshtml):

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

and an editor template for type Dervied2( ~/Views/Home/EditorTemplates/Derived2.cshtml):

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

Now all that remains is a custom mediator that will use the value of the hidden field to create the correct type in the collection:

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

which will be registered in Application_Start:

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

All Articles