【问题标题】:ViewModel with List<BaseClass> and editor templates带有 List<BaseClass> 和编辑器模板的 ViewModel
【发布时间】:2011-06-26 15:49:09
【问题描述】:

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

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

我对每个派生类型都有一个部分视图,并给出了混合派生类型的List,框架知道如何呈现它们。

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

以前有人试过吗?

【问题讨论】:

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


【解决方案1】:

假设您有以下模型:

public abstract class TableInputModel 
{ 

}

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

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

还有以下控制器:

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

现在您可以编写视图了。

主视图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 类型的自定义模型绑定器,它将使用发布的隐藏字段值来获取类型并实例化正确的实现:

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 操作中,模型数组将使用正确的类型正确初始化。

【讨论】:

  • 干杯,看起来我离目标不远了。你假设的代码是正确的:)
  • TableInputModel 的数组是否是更大 InputModel 的一部分 - 而不是用作发布操作的直接参数?
  • @iwayneo,不,该数组可能是另一个视图模型的属性。您可能只需要查看并调整模型绑定器中的前缀。
  • 好的 - 我做了一个测试项目:github.com/wayne-o/BindingTest 并且按预期工作......我需要剥离我的真实项目并找出阻止它在那里工作的原因。感谢您的帮助。
  • 仅作记录:bindingContext.ModelName 可能为空,因此在这种情况下您必须删除 Propertyname 之前的点。
【解决方案2】:

在 mvccontrib 中有 "Derived Type Model Binder"。但是,不幸的是,在 mvccontrib 版本 3 中没有这样的绑定器

【讨论】:

  • 其实是这样,但是API和mvccontrib2相比变化很大
猜你喜欢
  • 2011-07-15
  • 2011-10-16
  • 1970-01-01
  • 2014-02-13
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多