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

时间:2022-10-28 04:05:13

I have read many articles about using MultiSelectList and have yet to understand what is going wrong with my DropDownListFor. I have a ListBoxFor with the same View, ViewModel and data that works fine. I want to use the DropDownListFor because of its optionLabel parameter that ListBoxFor doesn't have.

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

When the View is first loaded, both the DropDownListFor and the ListBoxFor show the multiple selected items.

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

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

When the Submit button is clicked, the selected items collection is posted back to the Controller action okay and the view is refreshed with the ListBoxFor still showing both selected items but the DropDownListFor is only showing one selected item.

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

为什么DropDownListFor会在提交后丢失多个选择,但ListBoxFor却没有? The controller action is constructing the MultiSelectList like this:

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

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

The View code looks like this:

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>

Why does the DropDownListFor lose the multiple selection after Submit but the ListBoxFor doesn't?

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

1 个解决方案

#1


18  

As the names of the methods imply, DropDownListFor() is for creating a <select> (to select 1 option) and ListBoxFor() is for creating a <select multiple> (to select multiple options). While both methods share a lot of common code, they do produce different results.

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

Adding the multiple="multiple" attribute changes the display, but it does not change the functionality of the code executed by these methods.

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

If you inspect the source code, you will note that all the overloads of DropDownListFor() ultimately call the private static MvcHtmlString DropDownListHelper() method, and similarly ListBoxFor() ultimately calls the private static MvcHtmlString ListBoxHelper() method.

如果检查源代码,您会注意到DropDownListFor()的所有重载最终都会调用私有静态MvcHtmlString DropDownListHelper()方法,类似的ListBoxFor()最终会调用私有静态MvcHtmlString ListBoxHelper()方法。

Both these methods call the private static MvcHtmlString SelectInternal() method, but the difference is that DropDownListHelper() passes allowMultiple = false while the ListBoxHelper() passes allowMultiple = true.

这两个方法都调用私有静态MvcHtmlString SelectInternal()方法,但区别在于DropBownListHelper()传递allowMultiple = false,而ListBoxHelper()传递allowMultiple = true。

Within the SelectInternal() method, the key line of code is

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

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

The value of defaultValue is then used when building html for the <option> elements and is used to set the selected attribute(s).

然后在为

In the case of ListBoxFor(), the value of defaultValue will be the array defined by your SelectedAssignees property. In the case of DropDownListFor() it returns null because the value of your property cannot be cast to string (its an array).

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

Because defaultValue is null, none of the <option> elements have the selected attribute set and you lose model binding.

因为defaultValue为null,所以

As a side note, if you were to set the values of SelectedAssignees in the GET method before you pass the model to the view, you will see that none of them are selected when using DropDownListFor() for the same reasons described above.

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

Note also that the code for generating the SelectList should just be

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

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

There is no point setting the 3rd parameter when using either the DropDownListFor() or ListBoxFor() methods because its the value of the property your binding to (SelectedAssignees) that determines which options are selected (the 3rd parameter is ignored by the methods). If you want the options matching those Guid values to be selected, then in the GET method, use

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

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

#1


18  

As the names of the methods imply, DropDownListFor() is for creating a <select> (to select 1 option) and ListBoxFor() is for creating a <select multiple> (to select multiple options). While both methods share a lot of common code, they do produce different results.

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

Adding the multiple="multiple" attribute changes the display, but it does not change the functionality of the code executed by these methods.

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

If you inspect the source code, you will note that all the overloads of DropDownListFor() ultimately call the private static MvcHtmlString DropDownListHelper() method, and similarly ListBoxFor() ultimately calls the private static MvcHtmlString ListBoxHelper() method.

如果检查源代码,您会注意到DropDownListFor()的所有重载最终都会调用私有静态MvcHtmlString DropDownListHelper()方法,类似的ListBoxFor()最终会调用私有静态MvcHtmlString ListBoxHelper()方法。

Both these methods call the private static MvcHtmlString SelectInternal() method, but the difference is that DropDownListHelper() passes allowMultiple = false while the ListBoxHelper() passes allowMultiple = true.

这两个方法都调用私有静态MvcHtmlString SelectInternal()方法,但区别在于DropBownListHelper()传递allowMultiple = false,而ListBoxHelper()传递allowMultiple = true。

Within the SelectInternal() method, the key line of code is

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

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

The value of defaultValue is then used when building html for the <option> elements and is used to set the selected attribute(s).

然后在为

In the case of ListBoxFor(), the value of defaultValue will be the array defined by your SelectedAssignees property. In the case of DropDownListFor() it returns null because the value of your property cannot be cast to string (its an array).

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

Because defaultValue is null, none of the <option> elements have the selected attribute set and you lose model binding.

因为defaultValue为null,所以

As a side note, if you were to set the values of SelectedAssignees in the GET method before you pass the model to the view, you will see that none of them are selected when using DropDownListFor() for the same reasons described above.

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

Note also that the code for generating the SelectList should just be

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

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

There is no point setting the 3rd parameter when using either the DropDownListFor() or ListBoxFor() methods because its the value of the property your binding to (SelectedAssignees) that determines which options are selected (the 3rd parameter is ignored by the methods). If you want the options matching those Guid values to be selected, then in the GET method, use

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

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