Ajax表单总是发布带有空值的ViewModel(MVC 4)

时间:2015-03-23 20:12:01

标签: c# ajax asp.net-mvc

每当我提交表单时,控制器操作中的ViewModel对象都具有ViewModel中每个字段的空(或默认)值。 ViewModel对象本身不为null,但其所有值都为null或default(对于整数为0,对于DateTimes为1/1/0001 12:00:00 AM等)。

在谷歌搜索此问题并看到各种建议后,我确​​认了以下内容:

  • 模型状态有效。
  • 每个字段的HTML标记中的名称与ViewModel中的参数名称完全匹配(NewItem.ID,NewItem.AnotherID等)。
  • 更改参数名称无效。

为什么ViewModel值未正确发布?

这就是我所拥有的:

PaneViewModel

public class PaneViewModel
{
    public ViewModel NewItem { get; set; }
    public DataTableViewModel DataTable { get; set; }
}

视图模型

[Table("TableName")]
public class ViewModel
{
    [Key]
    [Column(Order = 0)]
    [DisplayName("ID")]
    public int ID { get; set; }

    [Key]
    [Column(Order = 1)]
    [DisplayName("AnotherID")]
    public int AnotherID { get; set; }

    [Key]
    [Column(Order = 2)]
    [DisplayName("Some Date")]
    public DateTime SomeDate { get; set; }

    [Required]
    [DisplayName("Another Date")]
    public DateTime AnotherDate { get; set; }

    [DisplayName("A Third Date")]
    public DateTime? AThirdDate { get; set; }
}

查看

@using (Ajax.BeginForm("AddItem", "Controller", new AjaxOptions
{
    UpdateTargetId = "add-item-section",
    LoadingElementId = "loading-image",
    HttpMethod = "POST",
}))
{
    <section id="add-item-section">
        <table>
            <tr>
                <th>@Html.LabelFor(m => m.NewItem.SomeDate)</th>
                <th>@Html.LabelFor(m => m.NewItem.AnotherDate)</th>
                <th>@Html.LabelFor(m => m.NewItem.AThirdDate)</th>
                <th></th>
            </tr>
            @Html.EditorFor(m => m.NewItem, "ViewModelEditorTemplate")
        </table>
    </section>
}

查看模型编辑器模板

@model ViewModel

<tr>
    <td>@Html.EditorFor(m => m.SomeDate)</td>
    <td>@Html.EditorFor(m => m.AnotherDate)</td>
    <td>@Html.EditorFor(m => m.AThirdDate)</td>
    <td><button type="submit" class="btn btn-info">Add</button></td>
</tr>

@Html.HiddenFor(m => m.ID)
@Html.HiddenFor(m => m.AnotherID)

控制器

[HttpPost]
public ActionResult AddItem(ViewModel item)
{
    // Breakpoint set here (code removed because it's irrelevant to this issue).
}

2 个答案:

答案 0 :(得分:1)

Model绑定器将尝试将这些名称NewItem.ID等与ViewModel类的属性进行匹配。不幸的是,Model绑定器在绑定到您的对象时不会自动知道删除NewItem前言。

如果接受ParentViewModel类型的对象(或者调用初始模型的任何对象),这应该允许Model绑定器使用表单中的属性正确初始化ParentViewModel.NewItem

[HttpPost]
public ActionResult AddItem(ParentViewModel item)
{
   ViewModel newItem = item.NewItem;// <-- bound using the name to properties mapping
}

如果不希望这样,您可以随时实现自定义模型绑定器,但这可能对此问题有点过分。

编辑

Stephen还指出了使用binding prefix明确告诉ModelBinder在属性之前预期NewItem的替代方法。

[HttpPost]
public ActionResult AddItem([Bind(Prefix="NewItem")]ViewModel item)
{
   //item should be bound using the properties correctly
}

根据您的偏好,这些解决方案中的任何一个都适合您。

答案 1 :(得分:-1)

从我所看到的,你忘了为ajax调用实例化Form。为此,请使用帮助程序Ajax.BeginForm,如下例所示。

@using (Ajax.BeginForm("MyAction", "MyController",
        new AjaxOptions {
            HttpMethod = "POST",
            InsertionMode = InsertionMode.Replace,
            UpdateTargetId = "target"})) 
{
        <tr>
            <td>@Html.EditorFor(m => m.SomeDate)</td>
            <td>@Html.EditorFor(m => m.AnotherDate)</td>
            <td>@Html.EditorFor(m => m.AThirdDate)</td>
            <td><button type="submit" class="btn btn-info">Add</button></td> 
        </tr>
        @Html.HiddenFor(m => m.ID) 
        @Html.HiddenFor(m => m.AnotherID)  
}

有关Ajax帮助程序的更多信息,请访问http://www.blackbeltcoder.com/Articles/script/using-ajax-beginform-with-asp-net-mvc