c# - 使用局部 View 时 MVC 模型 Null on post

标签 c# asp.net-mvc asp.net-mvc-4

我有一个 MVC Controller ,其中 post 方法上的模型总是返回 null。我不确定这是否是因为我在表单中使用了部分 View 。

知道为什么模型没有返回给 Controller 吗?

型号

enter image description here

加载模型

public List<Group> GetStaticMeasures(int businessUnitID)
{
    List<Group> groups = ctx.Groups
                           .Include("Datapoints")
                           .Where(w => w.BusinessUnitID.Equals(businessUnitID))
                           .OrderBy(o => o.SortOrder).ToList();

    groups.ForEach(g => g.Datapoints = g.Datapoints.OrderBy(d => d.SortOrder).ToList());

    return groups;
}

Controller

public ActionResult Data()
{
    ViewBag.Notification = string.Empty;

    if (User.IsInRole(@"xxx\yyyyyy"))
    {
        List<Group> dataGroups = ctx.GetStaticMeasures(10);
        return View(dataGroups);
    }
    else
    {
        throw new HttpException(403, "You do not have access to the data.");
    }
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Data(List<Group> model)
{
    ViewBag.Notification = string.Empty;

    if (User.IsInRole(@"xxx\yyyyyy"))
    {
        if (ModelState.IsValid)
        {
            ctx.SaveChanges(model);
            ViewBag.Notification = "Save Successful";
        }
    }
    else
    {
        throw new HttpException(403, "You do not have access to save the data.");
    }

    return View(model);
}

主视图

@model List<Jmp.StaticMeasures.Models.Group>

<div class="row">
    @using (Html.BeginForm())
    { 
        @Html.AntiForgeryToken()
        @Html.ValidationSummary(true)     

        <div class="large-12">
            <div class="large-8 large-centered columns panel">
                @foreach (var g in @Model)
                { 
                    <h2>@g.Name</h2>
                    foreach (var d in g.Datapoints)
                    { 
                        @Html.Partial("Measures", d)                                 
                    }
                    <hr />
                }   

                <input type="submit" class="button" value="Save Changes"/>

            </div>
        </div>    
    }
</div>

局部 View

@model Jmp.StaticMeasures.Models.Datapoint

@Html.HiddenFor(d => d.ID)
@Html.HiddenFor(d => d.Name) 
@Html.HiddenFor(d => d.SortOrder)

@Html.DisplayTextFor(d => d.Name)
@Html.EditorFor(d => d.StaticValue)   
@Html.ValidationMessageFor(d => d.StaticValue)                      

呈现的 Html 显示连续的 ID

enter image description here

最佳答案

正如您正确指出的那样,这是因为您使用的是部分。发生这种情况是因为 Html.Partial 不知道它在集合上运行,因此它不会为您的表单元素生成名称以绑定(bind)到集合。

但是,您的案例中的修复似乎相当简单。无需使用 Html.Partial,您只需将部分内容更改为 EditorTemplate 并在该模板上调用 Html.EditorForHtml.EditorFor 足够聪明,知道它何时处理一个集合,因此它会为集合中的每个项目调用您的模板,在您的表单上生成正确的名称。

因此,要执行您需要的操作,请按照以下步骤操作:

  1. 在 View 的当前文件夹中创建一个 EditorTemplates 文件夹(例如,如果您的 View 是 Home\Index.cshtml,则创建文件夹 Home\EditorTemplates).该名称很重要,因为它遵循查找模板的约定。
  2. 将您的部分 View 放在该文件夹中。或者,将其放在 Shared\EditorTemplates 文件夹中。
  3. 将您的部分 View 重命名为 Datapoint.cshtml(这很重要,因为模板名称基于类型名称的约定)。

现在相关的 View 代码变为:

// Note:  I removed @ from Model here.
@foreach (var g in Model)
{ 
    <h2>@g.Name</h2>
    @Html.EditorFor(m => g.DataPoints)
    <hr />
}

这确保了 View 的分离,正如您最初预期的那样。

根据评论更新

好吧,正如我在下面提到的,现在的问题是模型绑定(bind)器无法将 DataPoint 与正确的 Group 相关联。简单的解决方法是将 View 代码更改为:

for (int i = 0; i < Model.Count; i++)
{ 
    <h2>@Model[i].Name</h2>
    @Html.EditorFor(m => m[i].DataPoints)
    <hr />
}

这将正确生成名称,并且应该可以解决模型绑定(bind)问题。

OP 的附录

在 John 的回答之后,我还在 Group 表中包含了缺失的属性作为 HiddenFor's which game me the model back on the post。

@for (int i = 0; i < Model.Count(); i++)
{ 
    @Html.HiddenFor(t => Model[i].ID)
    @Html.HiddenFor(t => Model[i].BusinessUnitID)
    @Html.HiddenFor(t => Model[i].SortOrder)
    @Html.HiddenFor(t => Model[i].Name)

    <h2>@Model[i].Name</h2>
    @Html.EditorFor(m => Model[i].Datapoints)                                 
    <hr />                    
}

更新 2 - 更清洁的解决方案

我对每个 DataPoint 使用 EditorTemplate 的建议也适用于每个 Group。不需要 for 循环,再次在 View 中添加逻辑,您可以通过为 Group 设置一个 EditorTemplate 来完全避免这种情况。就放置模板的位置而言,适用与上述相同的步骤。

在这种情况下,模板将是 Group.cshtml,如下所示:

@model Jmp.StaticMeasures.Models.Group

<h2>@Model.Name</h2>
@Html.EditorFor(m => m.DataPoints)
<hr />

如上所述,这将为集合中的每个项目调用模板,这还将为每个 Group 生成正确的索引。您的原始 View 现在可以简化为:

@model List<Jmp.StaticMeasures.Models.Group>

@using (Html.BeginForm())
{
    // Other markup
    @Html.EditorForModel();
}

关于c# - 使用局部 View 时 MVC 模型 Null on post,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21574961/

相关文章:

jquery - 客户端验证不适用于重用和嵌套的复杂属性

c# - 函数返回类型 A,使其成为类型 B(继承自 A)

jquery - ASP.NET MVC 中带有复选框的 DropDown(组合框)

javascript - Asp mvc razor 在文本框中存储输入文件的值

javascript - md-autocomplete 搜索本地(浏览器对象),如果找不到,则查找数据库对象

asp.net-mvc - 根据用户角色类型更改布局

c# - 关于类中字符串的 Getter 或 Const 的设计建议 - 其他人在做什么?

c# - 'as' 关键字的用例

c# - 如何在不将图片保存到硬盘的情况下在 gridview 行中显示图片?

c# - MVC 4 中的自定义错误