【问题标题】:Why does the DropDownListFor lose the multiple selection after Submit but the ListBoxFor doesn't?为什么 DropDownListFor 在提交后会丢失多选而 ListBoxFor 不会?
【发布时间】:2018-02-10 10:55:24
【问题描述】:

我已经阅读了许多关于使用 MultiSelectList 的文章,但还没有理解我的 DropDownListFor 出了什么问题。我有一个 ListBoxFor,它具有相同的 View、ViewModel 和工作正常的数据。我想使用 DropDownListFor 因为 ListBoxFor 没有它的 optionLabel 参数。

第一次加载视图时,DropDownListFor 和 ListBoxFor 都会显示多个选定项。

当单击提交按钮时,选定的项目集合会被发送回控制器操作,并且视图会刷新,ListBoxFor 仍然显示两个选定的项目,但 DropDownListFor 只显示一个选定的项目。

控制器操作正在构造 MultiSelectList,如下所示:

vm.TasksFilterGroup.Assignees = new MultiSelectList(employees, "Id", "FullName", new string[] { "51b6f06a-e04d-4f98-88ef-cd0cfa8a2757", "51b6f06a-e04d-4f98-88ef-cd0cfa8a2769" });

查看代码如下所示:

<div class="form-group">
  <label>ListBoxFor</label>
  @Html.ListBoxFor(m => m.TasksFilterGroup.SelectedAssignees, Model.TasksFilterGroup.Assignees, new { @class = "form-control", multiple = "multiple" })
</div>
<div class="form-group">
  <label>DropDownListFor</label>
  @Html.DropDownListFor(m => m.TasksFilterGroup.SelectedAssignees, Model.TasksFilterGroup.Assignees, new { @class = "form-control", multiple = "multiple" })
</div>

为什么DropDownListFor在提交后会丢失多选而ListBoxFor不会?

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-5.2


    【解决方案1】:

    正如方法名称所暗示的,DropDownListFor() 用于创建 &lt;select&gt;(选择 1 个选项),ListBoxFor() 用于创建 &lt;select multiple&gt;(选择多个选项)。虽然这两种方法有很多共同的代码,但它们确实会产生不同的结果。

    添加multiple="multiple" 属性会更改显示,但不会更改这些方法执行的代码的功能。

    如果您检查source code,您会注意到DropDownListFor() 的所有重载最终都会调用private static MvcHtmlString DropDownListHelper() 方法,同样ListBoxFor() 最终会调用private static MvcHtmlString ListBoxHelper() 方法。

    这两种方法都调用private static MvcHtmlString SelectInternal()方法,但区别在于DropDownListHelper()传递allowMultiple = false,而ListBoxHelper()传递allowMultiple = true

    SelectInternal()方法中,关键的代码行是

    object defaultValue = (allowMultiple) ? htmlHelper.GetModelStateValue(fullName, typeof(string[])) : htmlHelper.GetModelStateValue(fullName, typeof(string));
    

    然后在为&lt;option&gt; 元素构建html 时使用defaultValue 的值,并用于设置selected 属性。

    对于ListBoxFor()defaultValue 的值将是您的SelectedAssignees 属性定义的数组。对于DropDownListFor(),它返回null,因为您的属性值不能转换为string(它是一个数组)。

    因为defaultValuenull,所以&lt;option&gt; 元素都没有selected 属性集,您将失去模型绑定。

    附带说明,如果您在将模型传递给视图之前在 GET 方法中设置 SelectedAssignees 的值,您将看到在使用 DropDownListFor() 时没有选择任何值,原因相同如上所述。

    还要注意,生成SelectList 的代码应该是

    vm.TasksFilterGroup.Assignees = new SelectList(employees, "Id", "FullName" });
    

    在使用DropDownListFor()ListBoxFor() 方法时设置第三个参数没有意义,因为它是您绑定到(SelectedAssignees) 的属性的值,它决定了选择哪些选项(第三个参数被忽略通过方法)。如果您希望选择匹配那些 Guid 值的选项,那么在 GET 方法中,使用

    vm.TasksFilterGroup.SelectedAssignees= new string[]{ "51b6f06a-e04d-4f98-88ef-cd0cfa8a2757", "51b6f06a-e04d-4f98-88ef-cd0cfa8a2769" };
    

    【讨论】:

    • 我们非常感谢这种彻底且知识渊博的回应。谢谢。
    • 这是一个伟大而深入的答案。很有见地。
    • 谢谢,描述得很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-11
    • 2016-04-15
    相关资源
    最近更新 更多