asp.net-mvc - 带有 List<BaseClass> 和编辑器模板的 ViewModel

标签 asp.net-mvc asp.net-mvc-3 viewmodel model-binding

我有一个 View ,其中列出了添加到平面图中的表格。表格派生自 TableInputModel,以允许 RectangleTableInputModelCircleTableInputModel

ViewModel 有一个 TableInputModel 列表,它们都是派生类型之一。

我有每个派生类型的部分 View ,并且给定混合派生类型的List,框架知道如何呈现它们。

但是,提交表单后,类型信息会丢失。我尝试过使用自定义模型绑定(bind)器,但由于类型信息在提交时丢失,因此无法工作...

以前有人尝试过吗?

最佳答案

假设您有以下型号:

public abstract class TableInputModel 
{ 

}

public class RectangleTableInputModel : TableInputModel 
{
    public string Foo { get; set; }
}

public class CircleTableInputModel : TableInputModel 
{
    public string Bar { get; set; }
}

以及以下 Controller :

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new TableInputModel[]
        {
            new RectangleTableInputModel(),
            new CircleTableInputModel()
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(TableInputModel[] model)
    {
        return View(model);
    }
}

现在您可以编写 View 了。

主视图Index.cshtml:

@model TableInputModel[]
@using (Html.BeginForm())
{
    @Html.EditorForModel()
    <input type="submit" value="OK" />
}

以及相应的编辑器模板。

~/Views/Home/EditorTemplates/RectangleTableInputModel.cshtml:

@model RectangleTableInputModel
<h3>Rectangle</h3>
@Html.Hidden("ModelType", Model.GetType())
@Html.EditorFor(x => x.Foo)

~/Views/Home/EditorTemplates/CircleTableInputModel.cshtml:

@model CircleTableInputModel
<h3>Circle</h3>
@Html.Hidden("ModelType", Model.GetType())
@Html.EditorFor(x => x.Bar)

最后缺少的和平是 TableInputModel 类型的自定义模型绑定(bind)器,它将使用发布的隐藏字段值来获取类型并实例化正确的实现:

public class TableInputModelBinder : 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(TableInputModel), new TableInputModelBinder());

这就是全部了。现在,在 Index Post 操作中,模型数组将使用正确的类型正确初始化。

关于asp.net-mvc - 带有 List<BaseClass> 和编辑器模板的 ViewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6484972/

相关文章:

c# - 在策略设计模式的情况下,Hangfire 服务器无法选择工作

ASP.NET MVC 如何在运行时添加新页面?

asp.net-mvc - ASP.NET MVC 中每个请求一个 DbContext(无 IOC 容器)

c# - 当 View 被渲染/实例化时通知 ViewModel

c# - 为什么 BaseController 的重载构造函数没有被执行?

c# - LINQ - 将组转换为数组

asp.net-mvc-3 - ASP.NET MVC Razor 渲染无需使用属性进行编码,即。数据注释

wpf - ViewModel 位置到子文件夹(XAML,命名空间)

c# - Razor页面如何找到DisplayNameFor中的字段?

c# - 统一: Cannot register type from different assembly