MVC Collection错过帖子

时间:2017-07-16 22:33:08

标签: c# asp.net-mvc asp.net-mvc-4 post mvc-editor-templates

我最近遇到了一些MVC4的行为,我希望能够获得一些观点。我实际项目中的行为使用了更复杂的对象,但我能够用简单的对象复制它,这就是我在这个问题中使用的。我的情况如下:

  1. 我有一个使用字符串集合作为其模型的视图。
  2. 我正在调用“EditorFor”来显示集合中的每个字符串。
  3. 在控制器中,我使用7个字符串项填充模型并将其传递给视图。
  4. 视图呈现所有7个项目。
  5. 我正在使用jquery从DOM中删除集合中的第二项。
  6. 我点击提交回发。
  7. 我检查了我发布的模型的内容,它只包含列表中的第一项。我希望列表中有6个项目(我从DOM中删除了7分钟)。
  8. 所述情况的代码如下:

    查看

    @model ICollection<string>
    
    @{
        ViewBag.Title = "Home Page";
    }
    
    @using (Html.BeginForm("Index", "Home", FormMethod.Post))
    {
        @Html.EditorFor(x => x);
        <input id="btnSubmit" type="submit" value="Submit" />
    }
    

    控制器

    [HttpGet]
    public ActionResult Index()
    {
         List<string> vm = new List<string>
         {
             "one",
             "two",
             "threE",
             "four",
             "five",
             "six",
             "seven"
         };
    
         return View(vm);
    }
    
    [HttpPost]
    public ActionResult Index(List<string> vm)
    {
        return View(vm);
    }
    

    感谢任何帮助解决此问题的人。期待增加我对MVC的理解!

4 个答案:

答案 0 :(得分:2)

可能与 Strange behaviour in ASP.NET MVC: removing item from a list in a nested structure always removes the last item 重复

在回发时从列表中删除项目时,我不需要验证,所以我使用

ModelState.Clear();

返回视图的往返过程中的任何地方,这解决了我在这种情况下的问题。

答案 1 :(得分:1)

是列表绑定问题。
这是关于mvc:Model Binding To A List

中列表绑定的重要文章

答案 2 :(得分:0)

这是一个索引问题。

@model ICollection<string>    
@{
    ViewBag.Title = "Home Page";
}

@using (Html.BeginForm("Index", "Home", FormMethod.Post)) {
    @for(int index = 0; index < Mode.Count; i++) {
        @Html.EditorFor(x => x[index])
    }
    <input id="btnSubmit" type="submit" value="Submit" />
}

如果计划要删除项目,那么棘手的部分就是管理剩余的索引。

答案 3 :(得分:0)

使用Masound发布的答案中的信息,我能够为此问题创建解决方案。事实证明问题是我使用的是顺序集合,其中每个索引都依赖于前一个索引。因此,当我从集合中删除一个元素时,我丢失了指向其他项目的链接。

解决方案是使用非顺序集合,其中索引存储为DOM中的隐藏字段。使用此方法,MVC知道每个索引所在的位置,并且可以使用所有元素在帖子上重新创建集合。

解决方案的描述如下:

  1. 我有一个使用Test对象集合作为其模型的View。
  2. 我有一个帮助类,它输出集合中对象的索引。
  3. 我打电话给#34; EditorFor&#34;在集合中显示每个Test对象及其索引。
  4. 在控制器中,我使用7个字符串项填充模型并将其传递给视图。
  5. 视图呈现所有7个项目。
  6. 我使用jquery从DOM中删除集合中的第二个项目。
  7. 我点击提交回发。
  8. 我检查了我发布的模型的内容,它只包含6个项目,这就是我的期望。
  9. 我正在重新定向Get方法以刷新模型状态的绑定。我注意到索引将绑定到集合中的错误项目的行为。因此,如果您计划重新加载相同的视图,那么我建议您实施此解决方案以避免意外行为。
  10. 此解决方案的代码如下:

    test.cs中

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Web;
    
    namespace WebApplication2.Models
    {
        public class Test
        {
            [Required(ErrorMessage="Required")]
            public string str {get; set;}
        }
    }
    

    Test.cshtml

    @model WebApplication2.Models.Test
    @using WebApplication2.Helpers
    
    @{
        ViewBag.Title = "Test";
    }
    
    <div id="@Model.str">
        @Html.TextBoxFor(x => x.str)
        @Html.ValidationMessageFor(x => x.str)
        @Html.HiddenIndexerInputForModel()
    </div>
    

    Index.cshtml

    @model ICollection<WebApplication2.Models.Test>
    
    @{
        ViewBag.Title = "Home Page";
    }
    
    @using (Html.BeginForm("Index", "Home", FormMethod.Post))
    {
        @Html.EditorFor(x => x)
        <input id="btnSubmit" type="submit" value="Submit" />
    }
    

    控制器

    [HttpGet]
    public ActionResult Index()
    {
        List<Test> vm = (List<Test>)Session["Test"];
    
        if (vm == default(List<Test>))
        {
            vm = new List<Test>
            {
                new Test { str="one"},
                new Test { str="two"},
                new Test { str="three"},
                new Test { str="four"},
                new Test { str="five"},
                new Test { str="six"},
                new Test { str="seven"}
             };
             Session.Add("Test", vm);
        }                    
    
        return View(vm);
    }
    
    [HttpPost]
    public ActionResult Index(List<Test> vm)
    {
        Session.Add("Test", vm);
        return RedirectToAction("Index");
    }
    

    HtmlHelper.cs - 帮助从这里取出:http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

    public static class ListModelBindingExtensions
    {
        static Regex _stripIndexerRegex = new Regex(@"\[(?<index>\d+)\]", RegexOptions.Compiled);
    
        public static string GetIndexerFieldName(this TemplateInfo templateInfo)
        {
            string fieldName = templateInfo.GetFullHtmlFieldName("Index");
            fieldName = _stripIndexerRegex.Replace(fieldName, string.Empty);
            if (fieldName.StartsWith("."))
            {
                fieldName = fieldName.Substring(1);
            }
            return fieldName;
        }
    
        public static int GetIndex(this TemplateInfo templateInfo)
        {
            string fieldName = templateInfo.GetFullHtmlFieldName("Index");
            var match = _stripIndexerRegex.Match(fieldName);
            if (match.Success)
            {
                return int.Parse(match.Groups["index"].Value);
            }
            return 0;
        }
    
        public static MvcHtmlString HiddenIndexerInputForModel<TModel>(this HtmlHelper<TModel> html)
        {
                string name = html.ViewData.TemplateInfo.GetIndexerFieldName();
                object value = html.ViewData.TemplateInfo.GetIndex();
                string markup = String.Format(@"<input type=""hidden"" name=""{0}"" value=""{1}"" />", name, value);
                return MvcHtmlString.Create(markup);
        }
    }
    

    感谢所有帮助解决方案到来的人!