ASP.NET MVC模型在编辑器模板中绑定IList

A B*_*nch 8 asp.net-mvc modelbinders

我试图绑定一个列表,该列表是较大的视图模型的一部分,而不依赖于自定义模型绑定器.当我使用编辑器模板来构建输入列表时,生成的名称的格式不正确,默认绑定器可以使用.

而不是物品[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; }
}
Run Code Online (Sandbox Code Playgroud)

的Index.aspx

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

  <h2>Index</h2>

  <% using(Html.BeginForm()) 
  {%> 
    <%:Html.EditorFor(m => m.Items) %>
  <%}%>
</asp:Content>
Run Code Online (Sandbox Code Playgroud)

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>
<%
}%>
Run Code Online (Sandbox Code Playgroud)

产量

<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>
Run Code Online (Sandbox Code Playgroud)

编辑(操作方法)

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 } },
        { new Item { Id = Guid.NewGuid(), Name = "Item 3", Value = 30 } },
        { new Item { Id = Guid.NewGuid(), Name = "Item 4", Value = 40 } }
      }
    });
}
Run Code Online (Sandbox Code Playgroud)

编辑#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;
}
Run Code Online (Sandbox Code Playgroud)

的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>
Run Code Online (Sandbox Code Playgroud)

tin*_*oft 7

我已经理解了你的问题,我也可能有一个解决方案:)!

首先,让我通过检查框架的源代码向您解释我所学到的知识(检查开源项目的源代码以更好地理解某些事情的工作方式总是一个好主意).

1-)当使用简单的强类型 html助手(即除了EditorForDisplayFor之外的所有Html.xxxFor(...)方法)时,在定义要渲染的模型属性的lambda表达式中,生成的html元素的名称等于任何string遵循" model => ",减去" => " 之前的内容,也就是说:

  • 如果模型是集合,则为" model " 字符串
  • 或字符串" model. "(注意末尾的" . ")否则.

所以,例如:

<%: Html.TextBoxFor( m=>m.OneProperty.OneNestedProperty)%>
Run Code Online (Sandbox Code Playgroud)

将生成此html输出:

<input type="text" name="OneProperty.OneNestedProperty" ../>
Run Code Online (Sandbox Code Playgroud)

还有这个:

<%: Html.TextBoxFor( m=>m[0].OneProperty.OneNestedProperty)%>
Run Code Online (Sandbox Code Playgroud)

会产生这个:

<input type="text" name="[0].OneProperty.OneNestedProperty" ../>
Run Code Online (Sandbox Code Playgroud)

==>这部分解释了为什么在使用EditorFor时你有这个"奇怪的"html输出.

2-)当使用复杂的强类型助手(EditorFor和DisplayFor)时,相同的先前规则将应用于关联的局部视图(在您的情况下为ItemList.ascx)中,此外,所有生成的html元素将以后面的内容为前缀 "==>",如1-)中所述.

这里的前缀是" Items. ",因为你在你的打字视图中有这个(Index.aspx):

<%:Html.EditorFor(m => m.Items) %>
Run Code Online (Sandbox Code Playgroud)

==>这完全解释了输出,以及为什么默认绑定器不再适用于您的项目列表

该解决方案将是打破你的ItemWrapper参数在[HttpPost]的方法,到他的属性,然后使用绑定属性与他的前缀参数为每个复杂的属性,就像这样:

    [HttpPost]
    public string Index(string foo,[Bind(Prefix = "Items.")]IList<Item> items)
    {
        return "Hello";
    }
Run Code Online (Sandbox Code Playgroud)

(假设ItemWrapper还有一个名为Foo的类型为string 的简单属性)

为避免冲突,在post方法中列出属性时,我强烈建议您根据每个属性的名称命名您的参数(没有其他情况),就像我一样.

希望这会有所帮助!