在ASP.NET MVC中设置DropDownList的选定项

27

我注意到在asp.net MVC中似乎存在一个bug,或者说我做错了什么。我目前正在使用1.0版本,也许这是2.0版本将要解决的问题。不管怎样,我们开始吧。

当我的视图模型具有与下拉列表所声明的id相同名称的属性时,选定的项被忽略,渲染的html没有任何选择。不确定是否我做错了什么,但更改id的名称可以解决问题。我简化了示例,希望它清晰明了,否则请让我知道。

这是我的视图,其中声明的ID与我的模型中的列表具有相同的名称:

<table border="0" cellpadding="0" cellspacing="0">
   <tr>
      <td>
         <%= Html.DropDownList("IsMultipleServicers", Model.IsMultipleServicers) %>
      </td>
   </tr>
</table>

生成的 HTML

<table border="0" cellpadding="0" cellspacing="0">
      <tr>
         <td>
             <select id="IsMultipleServicers" name="IsMultipleServicers">
                <option value="false">No</option>
                <option value="true">Yes</option>
             </select>
         </td>
      </tr>
</table>

现在让我们做个小改变。我将把声明的 id 改为不同的内容。

这是我的视图:

<table border="0" cellpadding="0" cellspacing="0">
    <tr>
       <td>
          <%= Html.DropDownList("MultipleServicers", Model.IsMultipleServicers) %>
       </td>
    </tr>
</table>

现在呈现的HTML代码如下:

<table border="0" cellpadding="0" cellspacing="0">
   <tr>
      <td>
         <select id="IsMultipleServicers" name="IsMultipleServicers">
            <option value="false">No</option>
            <option selected="selected" value="true">Yes</option>
         </select>
      </td>
   </tr>
</table>

注意,现在我得到了一个选定的选项,它将是列表中的第二个元素。

这是我的ViewModel,将所有内容绑定在一起:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MVCProject.Models.ViewModels.Service
{
    public class ServiceViewModel : ViewModel
    {
         public List<SelectListItem> IsMultipleServicers { get; set; }
    }
}

这是我的操作:

[AcceptVerbs(HttpVerbs.Get)]
public virtual ActionResult Service()
{
   return View(new ServiceViewModel()
   {
      IsMultipleServicers = BuildBooleanSelectList(true)
   };
}

 private List<SelectListItem> BuildBooleanSelectList(bool isTrue)
 {
    List<SelectListItem> list = new List<SelectListItem>();

    if (isTrue)
    {
       list.Add(new SelectListItem() { Selected = false, Text = "No", Value = "false" });
       list.Add(new SelectListItem() { Selected = true, Text = "Yes", Value = "true" });
    }
    else
    {
       list.Add(new SelectListItem() { Selected = true, Text = "No", Value = "false" });
       list.Add(new SelectListItem() { Selected = false, Text = "Yes", Value = "true" });
    }
 return list;
  }
3个回答

44

我认为问题在于对 DropDownList 的重载方法存在混淆:

  1. Html.DropDownList(string name) 查找视图模型属性名为 name,类型为 IEnumerable<SelectListItem>。它将使用列表中被选中的项(SelectListItem.Selected == true),除非存在相同名称的表单提交值。

  2. Html.DropDownList(string name, IEnumerable<SelectListItem> selectList) 使用来自 selectList 的项,但不使用它们的选择值。所选值通过在视图模型(或提交数据)中解析 name 并将其与 SelectListItem.Value 进行匹配来找到。即使无法找到该值(或为null),它仍然不会使用 SelectListItems 列表中的所选值。

您的代码使用了第二个重载方法,但指定了一个不存在的“value”属性(“MultipleServicers”)。

要解决此问题,请使用第一个重载方法:

<%= Html.DropDownList("IsMultipleServicers") %>

或者,在您的视图模型中添加一个 string MultipleServicers 属性,并在您的控制器中填充它。我建议这个解决方案,因为它可以避免几个问题,包括初始显示、帖子显示以及将帖子数据映射到视图/帖子模型:

public class ServiceViewModel : ViewModel 
{ 
     public string MultipleServicers { get; set; } 
     public List<SelectListItem> IsMultipleServicers { get; set; } 
}

接下来是你的HTML代码:

<%= Html.DropDownList(Model.MultipleServicers, Model.IsMultipleServicers) %>

这个技术也适用于MVC2:

<%= Html.DropDownListFor(x => x.MultipleServicers, Model.IsMultipleServicers) %>

我希望这更明显一些...但现在它有意义了。谢谢。 - Piotr Kula
我建议您使用这个链接:http://www.c-sharpcorner.com/UploadFile/4d9083/creating-simple-cascading-dropdownlist-in-mvc-4-using-razor/ - Umit Kaya

9
我曾经遇到过同样的问题,使用Html.DropDownList(string name, IEnumerable selectList)重载方法。我的模型中有与下拉列表名称相同的属性。这种情况下,MVC会优先选择模型的属性值,而不是IEnumerable中每个条目的Selected属性。
解决方法是使用一个与属性名称不匹配的下拉列表名称。另一种解决方法是编写自己的扩展方法,忽略模型和视图状态,始终遵守Selected属性。

1
我以前不得不使用这种方法来进行快速修复,但我认为最好在之后回过头来重构你的视图模型,更好地利用Html.DropDownList的本意(尽管它可能会让人感到困惑)。 - chris raethke

2

DropDownList助手从模型中获取默认值。在第一种情况下,与名称对应的模型中的值是一个SelectList -- 这与列表中的任何项目都不匹配,它就是列表,因此没有选择任何值。在第二个例子中,您的模型不包括该名称的属性,因此无法使用模型中的值,并且默认为SelectList本身指示的状态。通常,我会在模型上有一个用于所选值的属性 -- 这成为默认值 -- 和另一个表示列表潜在值的属性。


很好的解释!我自己也采用了您的默认做法——这似乎是使事情明确的最佳方式,并简化了生成SelectListItem值的过程。 - Gerard ONeill

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接