MVC3 剃刀编辑器模板与抽象类



这是来自MVC3 Razor httppost返回复杂对象子集合的后续问题。

我举的例子非常简单。子集合实际上是全部来自抽象基类的对象集合。 因此,该集合具有基类列表。

我已经为每个派生类创建了一个模板,并尝试使用 如果 child 是类型,则将模板名称作为字符串给出。 模板呈现到视图,但不填充回发。

我不确定如何将 editorfor bit 与模板一起使用来选择正确的模板并将要编组回父容器内的子对象的信息。

您可以使用自定义模型绑定器。让我们举个例子。

型:

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

控制器:

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

查看 ( ~/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>
}

Dervied1类型的编辑器模板 ( ~/Views/Home/EditorTemplates/Derived1.cshtml ):

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

Dervied2类型的编辑器模板 ( ~/Views/Home/EditorTemplates/Derived2.cshtml ):

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

现在剩下的只是一个自定义模型绑定器,它将使用隐藏字段值来实例化集合中的正确类型:

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

将在Application_Start注册:

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