MVC集合发布后缺少项目 [英] MVC Collection Missing items on Post

查看:93
本文介绍了MVC集合发布后缺少项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近遇到了一些MVC4的行为,希望对此有所了解.我实际项目中的行为使用了更复杂的对象,但是我能够使用简单的对象来复制它,这就是我在此问题中所使用的.我的情况如下:

I've recently run into some behaviour with MVC4 that I'm hoping to gain some perspective on. The behaviour in my actual project uses more complex objects, but I was able to replicate it with simple objects, which is what I'm using in this question. My situation is as follows:

  1. 我有一个使用字符串集合作为其模型的视图.
  2. 我正在呼叫"EditorFor"以显示集合中的每个字符串.
  3. 在控制器中,我用7个字符串项填充模型并将其传递给视图.
  4. 该视图呈现所有7个项目.
  5. 我正在使用jquery从DOM中删除集合中的第二项.
  6. 我点击提交以发回邮件.
  7. 我检查了回发模型的内容,它仅包含列表中的第一项.我希望列表中有6项(从DOM中删除的项有7分钟).

所描述情况的代码如下:

The code for the described situation is as follows:

查看

@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的了解!

Thanks to anyone who helps out with this. Looking forward to increasing my understanding of MVC!

推荐答案

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

Using the information in the answer that Masound posted, I was able to create a solution to this problem. It turns out the problem is that I was using a sequential collection where each index relies on the previous one being present. So when I removed one element from the collection, I lost the link to the other items that proceed it.

解决方案是使用非顺序集合,其中索引存储为DOM中的隐藏字段.使用这种方法,MVC知道每个索引在哪里,并可以在发布时重新创建具有所有元素的集合.

The solution is to use a non sequential collection where the index is stored as a hidden field in the DOM. Using this method, MVC knows where each index lies and can recreate the collection on post with all the elements.

解决方案的说明如下:

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

此解决方案的代码如下:

The code for this solution is as follows:

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

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

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-帮助器来自此处:

HtmlHelper.cs - Helper was taken from here: 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);
    }
}

感谢所有为该解决方案的到来提供帮助的人!

Thanks to everyone who helped in the arrival of this solution!

这篇关于MVC集合发布后缺少项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆