简体   繁体   English

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

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

I have a class called CategoryModel , one of the properties of which is a list of objects of the same type. 我有一个名为CategoryModel ,其中一个属性是相同类型的对象列表。 So CategoryModel.Categories is of type List<CategoryModel> . 所以CategoryModel.Categories的类型为List<CategoryModel>

On the category index page, I display an editor for each category so that the user can change any of the category names without having to go to a dedicated page to do so. 在类别索引页面上,我为每个类别显示一个编辑器,以便用户可以更改任何类别名称,而无需转到专用页面来执行此操作。 Like so: 像这样:

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

And the editor template for CategoryModel looks like this: 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>

The problem I have is that submitting the form does not bind correctly to the Edit action of the CategoryController : 我遇到的问题是提交表单没有正确绑定到CategoryControllerEdit操作:

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

If I check the names on the hidden fields and textboxes, they are labelled based on their position in the current category (eg Categories[0].Name ). 如果我检查隐藏字段和文本框上的名称,它们将根据它们在当前类别中的位置进行标记(例如, Categories[0].Name )。 If I create a dedicated edit view, however, they are simply named according to the field name (eg Name ). 但是,如果我创建一个专用的编辑视图,则只需根据字段名称(例如NameName

I have tried changing the controller to accept a list of Categories: 我尝试更改控制器以接受类别列表:

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

This works if I submit the very first category, but none of the others (in those cases Categories is null). 如果我提交第一个类别,但是没有其他Categories (在这些情况下, Categories为null),则此方法有效。

I have also tried changing how I display my EditorFor, by doing this: 我也试过改变我如何显示我的EditorFor,这样做:

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

Which changes the field names to be the same for each category (eg all category names are called cat.Name ), which I believe is a step in the right direction. 这会将每个类别的字段名称更改为相同(例如,所有类别名称都称为cat.Name ),我认为这是朝着正确方向迈出的一步。

So how do I bind correctly to my controller? 那么如何正确绑定到我的控制器? I realise that I could submit the whole parent category and then save each subcategory, but this seems like a very inefficient way to submit a single change. 我意识到我可以提交整个父类别,然后保存每个子类别,但这似乎是提交单个更改的一种非常低效的方式。

I discovered how to do this. 我发现了如何做到这一点。 There is an overload for Html.EditorFor that allows you to specify the htmlFieldName property (the third parameter in the example below): Html.EditorFor有一个重载,它允许你指定htmlFieldName属性(下面例子中的第三个参数):

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

This renders all of the field names without any prefix and allows me to submit any single category successfully. 这将呈现所有字段名称,不带任何前缀,并允许我成功提交任何单个类别。

Your Edit action accept CategoryModel category so you need to reset model prefix for right binding. 您的“编辑”操作接受CategoryModel类别,因此您需要重置右侧绑定的模型前缀。 For this you need to create your own extension method for HtmlHelper like this: 为此,您需要为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);
        }
    }

And then use it inside your editor template: 然后在编辑器模板中使用它:

@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