【问题标题】:MVC EditorFor model binding for multiple edit forms on one pageMVC EditorFor一页上多个编辑表单的模型绑定
【发布时间】:2013-07-12 13:07:59
【问题描述】:

我有一个名为CategoryModel 的类,其中一个属性是相同类型对象的列表。所以CategoryModel.Categories 的类型是List<CategoryModel>。

在类别索引页面上,我为每个类别显示了一个编辑器,以便用户可以更改任何类别名称,而无需转到专用页面。像这样:

<ul id="categories>
    @Html.EditorFor(model => model.Categories)
</ul>

CategoryModel 的编辑器模板如下所示:

<li class="folder">
    @using (Html.BeginForm("Edit", "Category", new { id = Model.Key }, FormMethod.Post, new { @class = "ajaxoff"})) {
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.Key)
        @Html.HiddenFor(model => model.ParentKey)
        @Html.HiddenFor(model => model.Sequence)
        @Html.HiddenFor(model => model.IncludeDeleted)

        @Html.TextBoxFor(model => model.Name, null, new { @class = "catName" })
        @Html.ValidationMessageFor(model => model.Name)

        <input type="submit" value="Save" class="icon save" />
    }
</li>

我遇到的问题是提交表单没有正确绑定到CategoryController 的Edit 操作:

[HttpPost]
public ActionResult Edit(CategoryModel category)
{
    // At this point all properties in category are null
}

如果我检查隐藏字段和文本框上的名称,它们会根据它们在当前类别中的位置进行标记(例如Categories[0].Name)。但是,如果我创建一个专用的编辑视图,它们只是根据字段名称命名(例如Name)。

我已尝试更改控制器以接受类别列表:

[HttpPost]
public ActionResult Edit(List<CategoryModel> categories)
{
    var category = categories.First();
}

如果我提交第一个类别,但其他类别均不提交(在这些情况下,Categories 为空),则此方法有效。

我还尝试通过这样做来更改我的 EditorFor 的显示方式:

<ul id="categories>
    @foreach (var cat in Model.Categories)
    {
        @Html.EditorFor(model => cat);
    }
</ul>

这会将每个类别的字段名称更改为相同(例如,所有类别名称都称为cat.Name),我认为这是朝着正确方向迈出的一步。

那么如何正确绑定到我的控制器?我意识到我可以提交整个父类别,然后保存每个子类别,但这似乎是提交单个更改的一种非常低效的方式。

【问题讨论】:

    标签: c# asp.net-mvc razor model-binding


    【解决方案1】:

    我发现了如何做到这一点。 Html.EditorFor 有一个重载,允许您指定 htmlFieldName 属性(下例中的第三个参数):

    @foreach (var cat in Model.Categories)
    {
        @Html.EditorFor(model => cat, null, "");
    }
    

    这会呈现所有没有任何前缀的字段名称,并允许我成功提交任何单个类别。

    【讨论】:

    • 我这样做了,但字段名称后仍然出现 [0] 和 [1],您是如何处理的?
    • 我没有得到你描述的问题。但是,如果您使用 @Html.EditorFor(model => model.Categories, null, "") 而不是上面的循环,则在字段名称之前会得到 [0] 和 [1],因为您将数组传递给EditorFor 方法而不是单个模型。
    【解决方案2】:

    您的 Edit 操作接受 CategoryModel 类别,因此您需要重置模型前缀以进行右绑定。为此,您需要为 HtmlHelper 创建自己的扩展方法,如下所示:

    public class BeginHtmlScope : IDisposable
        {
            private readonly TemplateInfo templateInfo;
            private readonly string previousHtmlFieldPrefix;
    
            public BeginHtmlScope(TemplateInfo templateInfo, string htmlFieldPrefix)
            {
                this.templateInfo = templateInfo;
    
                previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
                templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
            }
    
            public void Dispose()
            {
                templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
    
            }
        }
        public static class MyHtmlExtensions
        {
            public static IDisposable BeginHtmlScope(this HtmlHelper html, string htmlFieldPrefix)
            {
                return new BeginHtmlScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
            }
        }
    

    然后在你的编辑器模板中使用它:

    @using (Html.BeginHtmlScope(""))
    {
       <li class="folder">
        @using (Html.BeginForm("Edit", "Category", new { id = Model.Key }, FormMethod.Post, new { @class = "ajaxoff"})) {
            @Html.ValidationSummary(true)
            @Html.HiddenFor(model => model.Key)
            @Html.HiddenFor(model => model.ParentKey)
            @Html.HiddenFor(model => model.Sequence)
            @Html.HiddenFor(model => model.IncludeDeleted)
    
            @Html.TextBoxFor(model => model.Name, null, new { @class = "catName" })
            @Html.ValidationMessageFor(model => model.Name)
    
            <input type="submit" value="Save" class="icon save" />
        }
    </li>
    
    }
    

    【讨论】:

    • 不幸的是,这与 foreach 循环有相同的问题 - 字段名称为 Categories[0].Name、Categories[1].Name 等,CategoryModel 不绑定到 Edit 操作。
    • 很抱歉误解了您的问题。我已经编辑了我的答案。
    猜你喜欢
    • 1970-01-01
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多