问题 ASP.NET MVC - 模型绑定一组动态生成的复选框 - 如何


我正在尝试建模绑定一组动态生成的复选框,以便在控制器操作中处理它们,但无法使模型绑定发生。这是场景:

我的ViewModel类(DocumentAddEditModel)包含一个字典(Dictionary <string,bool>),每个条目的字符串是每个复选框的名称/标签,以及指示是否选中该复选框的布尔值:

    public class DocumentAddEditModel
    {
        ...
        private Dictionary<string, bool> _categoryCheckboxes = new Dictionary<string,bool>();
        ...

        ...
        public Dictionary<string, bool> CategoryCheckboxes
        {
            get { return _categoryCheckboxes; }
            set { _categoryCheckboxes = value; }
        }
        ...
    }
}

在我的控制器中,处理表单的GET请求的操作填充了dictonary,如下所示:

public class DocumentsController : Controller
{
    [RequiresAuthentication]
    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult Add()
    {
        DocumentAddEditModel documentAddEditModel = new DocumentAddEditModel();
        ...
        Dictionary<string, bool> categoryCheckboxes = new Dictionary<string, bool>();
        ...
        string[] categories = Enum.GetNames(typeof(Category));

        foreach (string category in categories)
            categoryCheckboxes.Add(category, false);

        documentAddEditModel.CategoryCheckboxes = categoryCheckboxes;

        return View(documentAddEditModel);
    }
}

在视图中,我有以下内容来生成复选框:

<% foreach (KeyValuePair<string, bool> categoryCheckbox in ViewData.Model.CategoryCheckboxes)
    {%>
    <input class="checkbox" type="checkbox" name="CategoryCheckboxes[0].Key" id="<%= categoryCheckbox.Key %>" />
    <label class="categoryLabel" for="<%= categoryCheckbox.Key %>"><%= categoryCheckbox.Key %></label>
<% } %>

但我认为这是问题所在。不确定name属性中需要做什么。问题是,一旦在DocumentsController中回复到以下操作方法:

[RequiresAuthentication]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(DocumentAddEditModel documentAddEditModel)
{
    ...
}

documentAddEdit.Model.CategoryCheckboxes始终为null。我该如何设置它以使CategoryCheckboxes字典正确填充名称和复选框的已检查/未选中bool值?

谢谢


7754
2018-06-23 08:53


起源



答案:


如果您将复选框绑定到a Dictionary<string, bool> 尝试这个:

<% var i = 0; %>
<% foreach (KeyValuePair<string, bool> categoryCheckbox in Model.CategoryCheckboxes) {%>

    <input type="hidden" name="<%= String.Format("CategoryCheckboxes[{0}].Key", i) %>" value="<%= categoryCheckbox.Key %>" />
    <%= Html.CheckBox(String.Format("CategoryCheckboxes[{0}].Value", i), categoryCheckbox.Value) %>

    <label class="categoryLabel" for="<%= categoryCheckbox.Key %>"><%= categoryCheckbox.Key %></label>

    <% i++; %>
<% } %>

希望这可以帮助

更新:

用于绑定 IDictionary<T1, T2> 您的表单必须包含带有“CategoryCheckboxes [n] .Key”和“CategoryCheckboxes [n] .Value”Ids / Names的输入,其中n必须从零开始且不间断。


10
2018-06-23 10:12



感谢eu-ge-ne,这似乎可以解决问题,但是,你能否澄清一下这里发生了什么?我明白,因为复选框控件(<input type =“checkbox”...)没有'name'属性,模型绑定用于执行控件和viewmodel属性之间的映射,所以必须(?)使用隐藏领域。然而,有没有办法避免这样一个持有/传输状态的隐藏场?我后来不清楚的是如何传输复选框的真/假状态。 - Matthew
我再次意识到Html.CheckBox()htmlhelper生成第二个隐藏字段,其name属性等于可见复选框的名称属性,但是当我在未选中时将生成的html与复选框进行比较时: - Matthew
<input type =“hidden”name =“CategoryCheckboxes [0] .Key”value =“Article”/> <input id =“CategoryCheckboxes [0] _Value”name =“CategoryCheckboxes [0] .Value”type =“checkbox” value =“true”/> <input name =“CategoryCheckboxes [0] .Value”type =“hidden”value =“false”/> <label class =“categoryLabel”for =“Article”> Article </ label> - Matthew
检查时的内容:<input type =“hidden”name =“CategoryCheckboxes [0] .Key”value =“Article”/> <input checked =“checked”id =“CategoryCheckboxes [0] _Value”name =“ CategoryCheckboxes [0] .Value“type =”checkbox“value =”true“/> <input name =”CategoryCheckboxes [0] .Value“type =”hidden“value =”false“/> <label class =”categoryLabel“用于= “条”>文章</标签> - Matthew
唯一的区别是,在“已检查”状态下,“已检查”属性设置为“已检查”。保存实际数据的“值”属性不会更改。此外,是不是可以实现我想要的,而不必再次诉诸隐藏的元素(即不使用Html.Checkbox()帮助?)谢谢 - Matthew


答案:


如果您将复选框绑定到a Dictionary<string, bool> 尝试这个:

<% var i = 0; %>
<% foreach (KeyValuePair<string, bool> categoryCheckbox in Model.CategoryCheckboxes) {%>

    <input type="hidden" name="<%= String.Format("CategoryCheckboxes[{0}].Key", i) %>" value="<%= categoryCheckbox.Key %>" />
    <%= Html.CheckBox(String.Format("CategoryCheckboxes[{0}].Value", i), categoryCheckbox.Value) %>

    <label class="categoryLabel" for="<%= categoryCheckbox.Key %>"><%= categoryCheckbox.Key %></label>

    <% i++; %>
<% } %>

希望这可以帮助

更新:

用于绑定 IDictionary<T1, T2> 您的表单必须包含带有“CategoryCheckboxes [n] .Key”和“CategoryCheckboxes [n] .Value”Ids / Names的输入,其中n必须从零开始且不间断。


10
2018-06-23 10:12



感谢eu-ge-ne,这似乎可以解决问题,但是,你能否澄清一下这里发生了什么?我明白,因为复选框控件(<input type =“checkbox”...)没有'name'属性,模型绑定用于执行控件和viewmodel属性之间的映射,所以必须(?)使用隐藏领域。然而,有没有办法避免这样一个持有/传输状态的隐藏场?我后来不清楚的是如何传输复选框的真/假状态。 - Matthew
我再次意识到Html.CheckBox()htmlhelper生成第二个隐藏字段,其name属性等于可见复选框的名称属性,但是当我在未选中时将生成的html与复选框进行比较时: - Matthew
<input type =“hidden”name =“CategoryCheckboxes [0] .Key”value =“Article”/> <input id =“CategoryCheckboxes [0] _Value”name =“CategoryCheckboxes [0] .Value”type =“checkbox” value =“true”/> <input name =“CategoryCheckboxes [0] .Value”type =“hidden”value =“false”/> <label class =“categoryLabel”for =“Article”> Article </ label> - Matthew
检查时的内容:<input type =“hidden”name =“CategoryCheckboxes [0] .Key”value =“Article”/> <input checked =“checked”id =“CategoryCheckboxes [0] _Value”name =“ CategoryCheckboxes [0] .Value“type =”checkbox“value =”true“/> <input name =”CategoryCheckboxes [0] .Value“type =”hidden“value =”false“/> <label class =”categoryLabel“用于= “条”>文章</标签> - Matthew
唯一的区别是,在“已检查”状态下,“已检查”属性设置为“已检查”。保存实际数据的“值”属性不会更改。此外,是不是可以实现我想要的,而不必再次诉诸隐藏的元素(即不使用Html.Checkbox()帮助?)谢谢 - Matthew


隐藏的元素是asp.net的运作方式。在webforms版本中,它是ViewState,这是一个巨大的隐藏字段,在MVC中,每个控件的重量更轻,更直接的隐藏字段。我不确定这有什么不对或令人不安。不知何故,你必须保持状态,你可以做客户端或服务器端。我建议客户端提供非敏感信息,如果服务器在回发之间重新启动等,它仍将存在。


1
2017-08-08 17:21





更简单的事情:

@foreach (var pair in Model.CategoryCheckboxes)
{
    @Html.CheckBoxFor(m=>m.CategoryCheckboxes[pair.Key])
}

0
2018-02-15 10:50