mvc3 razor editortemplate with abstract classes

∥☆過路亽.° 提交于 2019-12-07 04:14:02

问题


this is a follow up question from MVC3 Razor httppost return complex objects child collections.

The example I gave was very simple. The child collection is actually a collection of objects that all come from an abstract base class. So the collection has a list of base classes.

I have created a template for each derived class and tried using if child is of type then give the template name as a string. The templates are rendered to the view but not populated on the post back.

I am not sure how I use the editorfor bit with the templates to choose the correct template and get the information to be marshalled back into the child objects within the parent container.


回答1:


You could use a custom model binder. Let's 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 the Dervied1 type (~/Views/Home/EditorTemplates/Derived1.cshtml):

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

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

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

Now all that's left is a custom model binder that will use the hidden field value to instantiate the proper 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());


来源:https://stackoverflow.com/questions/10555448/mvc3-razor-editortemplate-with-abstract-classes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!