为什么DropDownListFor在提交之后会失去多重select,但是ListBoxFor却没有?

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

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

初始视图

当提交button被点击时,所选项目集合被回发到控制器行为好,并且视图刷新与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在提交之后会失去多重select,但是ListBoxFor却没有?

正如方法名所暗示的, DropDownListFor()用于创build<select> (select1选项), ListBoxFor()用于创build<select multiple> (用于select多个选项)。 虽然这两种方法共享很多通用的代码,但它们确实产生了不同的结果。

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

如果你检查了源代码 ,你会注意到DropDownListFor()所有重载最终都会调用private static MvcHtmlString DropDownListHelper()方法,同样, ListBoxFor()最终调用private static MvcHtmlString ListBoxHelper()方法。

这两个方法都调用private static MvcHtmlString SelectInternal()方法,但差别在于,当ListBoxHelper()传递allowMultiple = trueDropDownListHelper()传递allowMultiple = false

SelectInternal()方法中,密钥的代码是

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

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

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

由于defaultValuenull ,所以<option>元素都没有selected属性集,并且会丢失模型绑定。

作为一个方面说明,如果在将模型传递给视图之前,您要在GET方法中设置SelectedAssignees的值,则出于上述相同原因使用DropDownListFor()时,您将看到没有选中它们。

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

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

当使用DropDownListFor()ListBoxFor()方法时,没有必要设置第三个参数,因为它的绑定属性的值( SelectedAssignees )决定select哪个选项(第三个参数被方法忽略)。 如果你想select匹配thode Guid值的选项,那么在GET方法中使用

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