为什么在提交后 DropDownListFor 会丢失多选但 ListBoxFor 不会? [英] Why does the DropDownListFor lose the multiple selection after Submit but the ListBoxFor doesn't?

查看:16
本文介绍了为什么在提交后 DropDownListFor 会丢失多选但 ListBoxFor 不会?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

控制器操作正在像这样构造 MultiSelectList:

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

查看代码如下所示:

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

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

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

解决方案

顾名思义,DropDownListFor() 用于创建一个 (选择多个选项).虽然这两种方法共享许多通用代码,但它们确实会产生不同的结果.

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

如果您检查源代码,你会注意到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 时使用,并用于设置 selected 属性(s).

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

因为 defaultValuenull 元素都没有设置 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" };

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.

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

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.

The controller action is constructing the MultiSelectList like this:

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:

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

解决方案

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.

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

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.

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.

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

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).

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

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.

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

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

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

这篇关于为什么在提交后 DropDownListFor 会丢失多选但 ListBoxFor 不会?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆