复杂模型和部分视图 - ASP.NET MVC 3中的模型绑定问题

45

我在我的MVC 3示例应用程序中有2个模型,SimpleModelComplexModel,如下所示:

public class SimpleModel
{
    public string Status { get; set; }
}

public class ComplexModel
{
    public ComplexModel()
    {
        Simple = new SimpleModel();
    }

    public SimpleModel Simple{ get; set; }
}

我为这个模型定义了视图:

_SimplePartial.cshtml:

@model SimpleModel

@Html.LabelFor(model => model.Status)
@Html.EditorFor(model => model.Status)

以及 Complex.cshtml:

@model ComplexModel

@using (Html.BeginForm()) {

    @Html.Partial("_SimplePartial", Model.Simple)
    <input type="submit" value="Save" />
}

提交表单后,即使在Status字段中输入了随机值,该值也未绑定到我的模型上。当我在控制器操作中检查模型时,Status字段为NULL

[HttpPost]
public ActionResult Complex(ComplexModel model)
{
    // model.Simple.Status is NULL, why ?
}
为什么它没有绑定?我不想继承模型。对于这种简单的情况,我必须编写自定义模型绑定器吗?
谢谢。

可以做到这一点,但是也许将Simple对象转换为某些东西,以便不可编辑所有字段? - icecreamsoop
2个回答

62

改为:

@Html.Partial("_SimplePartial", Model.Simple)

我建议您使用编辑器模板:

@model ComplexModel
@using (Html.BeginForm()) 
{
    @Html.EditorFor(x => x.Simple)
    <input type="submit" value="Save" />
}

然后将简单的局部视图放在~/Views/Shared/EditorTemplates/SimpleModel.cshtml~/Views/Home/EditorTemplates/SimpleModel.cshtml中,其中Home是您控制器的名称:

@model SimpleModel
@Html.LabelFor(model => model.Status)
@Html.EditorFor(model => model.Status)

当然,如果你更喜欢将这个部分放在某个特定的位置而不是遵循惯例(为什么会呢?),你可以指定位置:

@Html.EditorFor(x => x.Simple, "~/Views/SomeUnexpectedLocation/_SimplePartial.cshtml")

那么一切都会按照预期的方式进行。


1
看起来还不错,但有一个缺点。状态字段的id属性已从“Status”更改为“Simple_Status”。因此,我的JavaScript停止工作了。有没有办法告诉MVC不要更改元素的默认ID?由于我不会使用相同模型包含多个视图,因此ID始终是唯一的。尽管如此,也许更正确的方法是修复JS? - jwaliszko
1
答案很有用。但是@Html.EditorFor(x => x.Simple)将显示SimpleModel类的所有属性。但是如果我只想显示几个属性,应该如何实现? - Ovini
1
好的,但如果我想添加一个新项到集合中怎么办?当我点击添加新项的按钮时,我需要JavaScript。哪种方法最好? - Leandro De Mello Fagundes
1
如果您想在客户端进行动态列表编辑,请查看 Knockout 或 Angular。它们是客户端 MVC 框架。然后,您可以将带有动态列表的整个对象发布到服务器上。 - LockTar
1
似乎此问题中的“SomeUnexpectedLocation”路径不受EditorFor控件支持。 - jpsimard-nyx
显示剩余3条评论

26

正如Daniel Hall在他的博客中建议的那样, 传递一个 ViewDataDictionary,其中包含一个 TemplateInfo,将HtmlFieldPrefix设置为SimpleModel属性的名称:

 @Html.Partial("_SimplePartial", Model.Simple, new ViewDataDictionary(ViewData)
    {
        TemplateInfo = new System.Web.Mvc.TemplateInfo
        {
            HtmlFieldPrefix = "Simple"
        }
    })

1
public static ViewDataDictionary<T> WithFieldPrefix<T>(this ViewDataDictionary<T> viewData, string fieldPrefix) { return new ViewDataDictionary<T>(viewData) { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = fieldPrefix } }; } - James White
1
我喜欢这个答案,因为在复杂的模型中,我大多数时候需要使用Partial。 - kartal
1
这是要使用的! - EthR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接