为什么 DropDownListFor 在 Submit 后会丢失多选,而 ListBoxFor 不会?
Why does the DropDownListFor lose the multiple selection after Submit but the ListBoxFor doesn't?
我已经阅读了很多关于使用 MultiSelectList 的文章,但还没有理解我的 DropDownListFor 出了什么问题。我有一个 ListBoxFor,它具有相同的 View、ViewModel 和工作正常的数据。我想使用 DropDownListFor,因为它的 optionLabel 参数是 ListBoxFor 没有的。
首次加载视图时,DropDownListFor 和 ListBoxFor 都会显示多个选定项。
单击“提交”按钮后,所选项目集合将回发到 Controller 操作,并且视图会刷新,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在Submit之后会失去多选,而ListBoxFor却不会?
正如方法名称所暗示的那样,DropDownListFor()
用于创建 <select>
(至 select 1 个选项)而 ListBoxFor()
用于创建 <select multiple>
(至select多个选项)。虽然这两种方法共享许多通用代码,但它们确实会产生不同的结果。
添加 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));
然后在为 <option>
元素构建 html 时使用 defaultValue
的值,并用于设置 selected
属性。
在ListBoxFor()
的情况下,defaultValue
的值将是您的SelectedAssignees
属性定义的数组。在 DropDownListFor()
的情况下,它 returns null
因为你的 属性 的值不能转换为 string
(它是一个数组)。
因为 defaultValue
是 null
,<option>
元素中的 none 具有 selected
属性集,您失去了模型绑定。
作为旁注,如果在将模型传递给视图之前在 GET 方法中设置 SelectedAssignees
的值,您将看到其中 none 是 selected 当使用 DropDownListFor()
时出于与上述相同的原因。
另请注意,生成 SelectList
的代码应该只是
vm.TasksFilterGroup.Assignees = new SelectList(employees, "Id", "FullName" });
在使用 DropDownListFor()
或 ListBoxFor()
方法时设置第三个参数没有意义,因为它是 属性 绑定到 (SelectedAssignees
) 的值确定哪些选项是 selected(方法忽略第三个参数)。如果您希望匹配那些 Guid
值的选项被 selected,那么在 GET 方法中,使用
vm.TasksFilterGroup.SelectedAssignees= new string[]{ "51b6f06a-e04d-4f98-88ef-cd0cfa8a2757", "51b6f06a-e04d-4f98-88ef-cd0cfa8a2769" };
我已经阅读了很多关于使用 MultiSelectList 的文章,但还没有理解我的 DropDownListFor 出了什么问题。我有一个 ListBoxFor,它具有相同的 View、ViewModel 和工作正常的数据。我想使用 DropDownListFor,因为它的 optionLabel 参数是 ListBoxFor 没有的。
首次加载视图时,DropDownListFor 和 ListBoxFor 都会显示多个选定项。
单击“提交”按钮后,所选项目集合将回发到 Controller 操作,并且视图会刷新,ListBoxFor 仍显示两个所选项目,但 DropDownListFor 仅显示一个所选项目。
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在Submit之后会失去多选,而ListBoxFor却不会?
正如方法名称所暗示的那样,DropDownListFor()
用于创建 <select>
(至 select 1 个选项)而 ListBoxFor()
用于创建 <select multiple>
(至select多个选项)。虽然这两种方法共享许多通用代码,但它们确实会产生不同的结果。
添加 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));
然后在为 <option>
元素构建 html 时使用 defaultValue
的值,并用于设置 selected
属性。
在ListBoxFor()
的情况下,defaultValue
的值将是您的SelectedAssignees
属性定义的数组。在 DropDownListFor()
的情况下,它 returns null
因为你的 属性 的值不能转换为 string
(它是一个数组)。
因为 defaultValue
是 null
,<option>
元素中的 none 具有 selected
属性集,您失去了模型绑定。
作为旁注,如果在将模型传递给视图之前在 GET 方法中设置 SelectedAssignees
的值,您将看到其中 none 是 selected 当使用 DropDownListFor()
时出于与上述相同的原因。
另请注意,生成 SelectList
的代码应该只是
vm.TasksFilterGroup.Assignees = new SelectList(employees, "Id", "FullName" });
在使用 DropDownListFor()
或 ListBoxFor()
方法时设置第三个参数没有意义,因为它是 属性 绑定到 (SelectedAssignees
) 的值确定哪些选项是 selected(方法忽略第三个参数)。如果您希望匹配那些 Guid
值的选项被 selected,那么在 GET 方法中,使用
vm.TasksFilterGroup.SelectedAssignees= new string[]{ "51b6f06a-e04d-4f98-88ef-cd0cfa8a2757", "51b6f06a-e04d-4f98-88ef-cd0cfa8a2769" };