为什么DropDownListFor会在提交后丢失多个选择,但ListBoxFor不会?

时间:2016-11-21 16:53:59

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

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

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

Initial View

单击“提交”按钮时,所选项目集合将回发到Controller操作,并且视图将刷新,ListBoxFor仍显示两个选定项目,但DropDownListFor仅显示一个选定项目。

Refreshed View 控制器动作正在构建MultiSelectList,如下所示:

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

View代码如下所示:

<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不会?

1 个答案:

答案 0 :(得分:20)

正如方法名称所暗示的那样,DropDownListFor()用于创建<select>(用于选择1个选项),ListBoxFor()用于创建<select multiple>(用于选择多个选项)。虽然这两种方法共享许多通用代码,但它们确实会产生不同的结果。

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

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

这两种方法都调用private static MvcHtmlString SelectInternal()方法,但区别在于DropDownListHelper()通过allowMultiple = falseListBoxHelper()通过allowMultiple = true

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

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

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

对于ListBoxFor()defaultValue的值将是您的SelectedAssignees属性定义的数组。在DropDownListFor()的情况下,它会返回null,因为您的属性的值无法转换为string(它的数组)。

由于defaultValuenull,因此<option>个元素都没有设置selected属性,并且您失去了模型绑定。

作为旁注,如果您在将模型传递给视图之前在GET方法中设置SelectedAssignees的值,则在使用DropDownListFor()时将看到没有选择它们出于同样的原因。

另请注意,生成SelectList的代码应该是

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

使用DropDownListFor()ListBoxFor()方法时没有必要设置第3个参数,因为它绑定到(SelectedAssignees)的属性值决定了哪些选项被选中(方法忽略第3个参数)。如果您希望选择与Guid值匹配的选项,则在GET方法中使用

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