ViewModel在ASP.NET MVC 5中回传了一个空集合

3
    public class SaleItem
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class SalesDBContext
    {
        public static List<SaleItem> GetItems()
        {
            var items = new List<SaleItem>(){
                new SaleItem{Id=1,Name="Soap"},
                new SaleItem{Id=2,Name="Milk Power"},
                new SaleItem{Id=3,Name="Toothpaste"},
                new SaleItem{Id=4,Name="Ice Cream"}
            };
            return items.ToList();
        }
    }

    public class SalesViewModel
    {
        public string Item { get; set; }
        public List<SaleItem> itemlist { get; set; }
    }

我有一个名为SalesViewModel的类和一个用于生成虚拟数据的SalesDBContext。我想从下拉列表中选择项目并将其添加到列表中。为此,我创建了以下视图:

@model MVCDropdown.Models.SalesViewModel
@using MVCDropdown.Models

<form method="post">
    <p>
        @Html.DropDownListFor(model => model.Item, new SelectList(ViewBag.Items, "Id", "Name"), "--select--")
        <input type="submit" value="Add" />
    </p>
    <p>
        @if (Model.itemlist != null)
        {
            <table>
                @foreach (var s in Model.itemlist)
                {
                    <tr>
                        <td>@s.Name</td>
                    </tr>
                }
            </table>
        }
    </p>
</form>

控制器

        [HttpGet]
        public ActionResult Index()
        {
            SalesViewModel model = new SalesViewModel
            { 
                Item = "",
                itemlist = new List<SaleItem>()
            };
            PopDrodown();
            return View(model);
        }

        [HttpPost]
        public ActionResult Index(SalesViewModel vm)
        {
            var t = SalesDBContext.GetItems().Where(x => x.Id == Convert.ToInt32(vm.Item)).FirstOrDefault();
            vm.itemlist.Add(t);
            PopDrodown();
            return View(vm);
        }

        private void PopDrodown()
        {
            ViewBag.Items = SalesDBContext.GetItems();
        }
    在下拉列表下方应以表格形式显示添加到列表中的项目。
  • 但是,当我通过按“添加”将选择的项目从下拉列表提交后,在返回到控制器时,它会返回一个空的itemlist,之前添加的项目不复存在。如何避免这个问题?
1个回答

4

您的HTML表单中只有一个输入元素:下拉菜单。因此,当提交表单时,发送到控制器操作的唯一值是Item属性。如果您想发送集合,可以使用隐藏字段:

<table>
    @for (var i = 0; i < Model.itemlist.Count; i++)
    {
        <tr>
            <td>
                @Html.HiddenFor(x => x.itemlist[i].Id)
                @Html.HiddenFor(x => x.itemlist[i].Name)
                @Html.DisplayFor(x => x.itemlist[i].Name)
            </td>
        </tr>
    }
</table>

显然,如果用户不应编辑HTML表单内的值,则更好的方法是拥有一个POST视图模型,它仅包含用户可以修改的属性,并且您将从与GET操作中检索集合元素相同的位置检索它们。


它给了我一个错误:“对象引用未设置为对象的实例。” - Daybreaker
我忘记为“Id”和“Name”属性包含一个隐藏字段。确保你都有它们,并且使用了我的答案中所示的“for”循环,而不是“foreach”。 - Darin Dimitrov
我可以通过添加 if (vm.itemlist == null) vm.itemlist = new List<SaleItem>(); vm.itemlist.Add(t); 来避免这个错误。但是,你能告诉我为什么不能使用 foreach 循环吗? - Daybreaker
2
因为如果您使用foreach循环,将无法生成正确的隐藏字段name属性。您需要在标记中包含以下内容:<input type="hidden" name="itemlist[0].Id" value="1" />,...我邀请您阅读以下博客文章:http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/,以更好地熟悉ASP.NET MVC模型绑定器期望传入数据的电线格式,以重新填充您的视图模型集合。 - Darin Dimitrov
非常感谢。这是一个巨大的帮助。 - Daybreaker
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接