而不是物品[3].就像我期望它是物品.[3] .Id.如果我在没有编辑器模板的情况下构建列表,它将按预期工作.
我做的事情显然是错的,还是这只是Html.Hidden和Html.TextBox的怪癖?
public class ItemWrapper { [UIHint("ItemList")] public IList<Item> Items { get; set; } } public class Item { public Guid Id { get; set; } public string Name { get; set; } public int Value { get; set; } }
的Index.aspx
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2>Index</h2> <% using(Html.BeginForm()) {%> <%:Html.EditorFor(m => m.Items) %> <%}%> </asp:Content>
ItemList.ascx
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IList<Mvc2Test.Models.Item>>" %> <h4>Asset Class Allocation</h4> <% if(Model.Count > 0) { %> <table> <tbody> <% for(int i = 0; i < Model.Count; i++) {%> <tr> <td><%: Model[i].Name%></td> <td> <%: Html.HiddenFor(m => m[i].Id) %> <%: Html.TextBoxFor(m => m[i].Value) %> </td> </tr> <%}%> </tbody> </table> <% }%>
产量
<tr> <td>Item 4</td> <td> <input id="Items__3__Id" name="Items.[3].Id" type="hidden" value="f52a1f57-fca8-4bc5-a746-ee0cef4e05c2" /> <input id="Items__3__Value" name="Items.[3].Value" type="text" value="40" /> </td> </tr>
编辑(操作方法)
public ActionResult Test() { return View( new ItemWrapper { Items = new List<Item> { { new Item { Id = Guid.NewGuid(),Name = "Item 1",Value = 10 } },{ new Item { Id = Guid.NewGuid(),Name = "Item 2",Value = 20 } },Name = "Item 3",Value = 30 } },Name = "Item 4",Value = 40 } } } }); }
编辑#2
HttpPost动作
[HttpPost] public ActionResult Test(ItemWrapper w) { if(w.Items == null) Response.Write("Items was null"); else Response.Write("Items found " + w.Items.Count.ToString()); return null; }
的Index.aspx
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h4>Does Not Work</h4> <% using(Html.BeginForm("Test","Home")) {%> <%:Html.EditorFor(m => m.Items) %> <input type="submit" value-"Go" /> <%}%> <h4>Does Work</h4> <% using(Html.BeginForm("Test","Home")) {%> <table> <tbody> <% for(int i = 0; i < Model.Items.Count; i++) {%> <tr> <td><%: Model.Items[i].Name%></td> <td> <%: Html.HiddenFor(m => Model.Items[i].Id) %> <%: Html.TextBoxFor(m => Model.Items[i].Value) %> </td> </tr> <%}%> </tbody> </table> <input type="submit" value-"Go" /> <%}%> </asp:Content>
解决方法
首先,让我通过检查framework’s source code来解释我所学到的知识(检查开源项目的源代码以更好地理解某些事情的工作方式总是一个好主意).
1-)当使用简单的强类型html助手(即除了EditorFor和DisplayFor之外的所有Html.xxxFor(…)方法)时,在定义要渲染的模型属性的lambda表达式中,生成的html元素的名称等于任何string遵循“model =>”,减去“=>”之前的内容,也就是说:
>如果模型是集合,则为字符串“model”
>或字符串“model”. (注意最后的“.”)否则.
所以,例如:
<%: Html.TextBoxFor( m=>m.OneProperty.OneNestedProperty)%>
<input type="text" name="OneProperty.OneNestedProperty" ../>
还有这个:
<%: Html.TextBoxFor( m=>m[0].OneProperty.OneNestedProperty)%>
会产生这个:
<input type="text" name="[0].OneProperty.OneNestedProperty" ../>
==>这部分解释了为什么在使用EditorFor时你有这个“奇怪的”html输出.
2-)当使用复杂的强类型助手(EditorFor和DisplayFor)时,相同的先前规则将应用于关联的局部视图(在您的情况下为ItemList.ascx)中,此外,所有生成的html元素将以后面的内容为前缀“==>”,如1-)中所述.
这里的前缀是“Items.”,因为你在你的打字视图中有这个(Index.aspx):
<%:Html.EditorFor(m => m.Items) %>
==>这完全解释了输出,以及为什么默认活页夹不再适用于您的项目列表
解决方案是将[HttpPost]方法中的ItemWrapper参数分解为其属性,然后对每个复杂属性使用带有Prefix参数的Bind属性,如下所示:
[HttpPost] public string Index(string foo,[Bind(Prefix = "Items.")]IList<Item> items) { return "Hello"; }
(假设ItemWrapper还有一个名为Foo的类型为string的简单属性)
为避免冲突,在post方法中列出属性时,我强烈建议您根据每个属性的名称命名您的参数(没有其他情况),就像我一样.
希望这会有所帮助!