繁体   English   中英

MVC Editor在一个页面上为多个编辑表单进行模型绑定

[英]MVC EditorFor model binding for multiple edit forms on one page

我有一个名为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>

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

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

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

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

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

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

我也试过改变我如何显示我的EditorFor,这样做:

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

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

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

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

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

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

您的“编辑”操作接受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>

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM