2010-09-17 32 views
22

我知道其他人问过这个问题,但我完全糊涂了这个:ASP.NET MVC MultiSelectList使用选定的值不正确地选择

这显示没有值的下拉列表中选择:

<%= Html.DropDownList("items", new MultiSelectList(Model.AvailableItems, 
    "id", "name", Model.items), new { multiple = "multiple" })%> 

这将显示与我传递(Model.items)的值适当选择像我期望的下拉:

<%= Html.DropDownList("somethingelse", new MultiSelectList(Model.AvailableItems, 
    "id", "name", Model.items), new { multiple = "multiple" })%> 

但问题是,此款产品现已命名为“一些thingelse“当我POST。我知道我可以破解这个,但是怎么回事?

+1

相反的HTML设置多个的.DropDownList,你可以使用Html.ListBoxFor。由于Html.DropDownList将只设置其中一个要选择的项目。 – 2012-10-30 18:08:36

+0

@NikitaIgnatov谢谢。你的评论真的帮助了我很多。 – gfan 2015-09-26 07:17:28

回答

18

您遇到的问题是使用Model.Items作为参数。代码

<%= Html.DropDownList("items", new MultiSelectList(Model.AvailableItems, 
    "id", "name", Model.items), new { multiple = "multiple" })%> 

实际上并不像您所期望的那样工作。这是工作,因为下拉列表的名称是“项目”。这是因为有一个称为“items”的表单参数被发回给您的操作。该参数存储在动作的ViewState中(不要与ViewData混淆)。 Html.DropdownList()发现有一个ViewState参数与您命名下拉菜单时命名相同,并使用该ViewState参数来计算出所选值。 它完全忽略了您通过的Model.items。

如果任何人都可以解释不能覆盖默认行为的逻辑,那么我很乐意听到它。

所以,这是你的第一个问题。为了解决这个问题,你需要做的就是将下拉列表重命名为其他内容 - 就像你在第二个例子中所做的一样。现在你的第二个问题开始发挥作用:所选项目的列表必须是一个简单对象的集合(我认为它实际上需要是一个IEnumerable,但我不能100%确定)。

DropDownList()方法将尝试将这些选定值与AvailableItems集合中的值匹配。如果它不能这样做,它会尝试匹配文本。

所以,试试这个,看看它是否工作

<%= Html.DropDownList("somethingelse", new MultiSelectList(Model.AvailableItems, 
    "id", "name", Model.items.Select(c=> c.name)), new { multiple = "multiple" })%> 

好运

+3

如果您选择了多个项目,这不起作用。它简单地选择您选择的第一个,并忽略其余部分。见Darin的答案。 – Castrohenge 2011-07-20 20:10:04

+0

FINALY一个工作解决方案!我整个早上都在这个废话上失去了,谢谢;) – 2013-04-19 11:55:18

47

太少上下文你的问题提供的,但我会尽力表现出一个完整的工作示例:

型号:

public class Item 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class MyModel 
{ 
    public IEnumerable<int> SelectedItemIds { get; set; } 
    public IEnumerable<Item> AvailableItems { 
     get 
     { 
      return new[] 
      { 
       new Item { Id = 1, Name = "Item 1" }, 
       new Item { Id = 2, Name = "Item 2" }, 
       new Item { Id = 3, Name = "Item 3" }, 
      }; 
     } 
    } 
} 

控制器:

[HandleError] 
public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     var model = new MyModel 
     { 
      SelectedItemIds = new[] { 2, 3 } 
     }; 
     return View(model); 
    } 

    [HttpPost] 
    public ActionResult Index(IEnumerable<int> selectedItemIds) 
    { 
     var model = new MyModel 
     { 
      // Important: Don't ever try to modify the selectedItemIds here 
      // The Html helper will completely ignore it and use 
      // the POSTed values 
      SelectedItemIds = selectedItemIds 
     }; 
     return View(model); 
    } 
} 

查看:

<% using (Html.BeginForm()) { %> 
    <%= Html.ListBoxFor(x => x.SelectedItemIds, 
     new MultiSelectList(Model.AvailableItems, "Id", "Name")) %> 
    <input type="submit" value="GO" /> 
<% } %> 

请注意,如果要生成多重选择,则Html.ListBoxFor更适合。很明显,AvailableItems属性应该从存储库中获取。

+0

达林季米特洛夫谢谢你的一切帮助..你无处不在.. :) – yusuf 2013-05-23 08:06:41

+0

质量的答案。 – radbyx 2014-06-17 10:49:17

+0

在MVC5中做了些改变,因为这个确切的答案不再有效。 – YesMan85 2014-07-06 04:34:26

5

我有同样的问题,我用我自己的extention方法来生成html和问题解决

public static MvcHtmlString ListBoxMultiSelectFor<TModel, TProperty>(
     this HtmlHelper<TModel> helper, 
     Expression<Func<TModel, TProperty>> expression, 
     IEnumerable<SelectListItem> selectList, 
     object htmlAttributes) 
    { 
     return ListBoxMultiSelectFor(helper, expression, selectList, new RouteValueDictionary(htmlAttributes)); 
    } 

    public static MvcHtmlString ListBoxMultiSelectFor<TModel, TProperty>(
     this HtmlHelper<TModel> helper, 
     Expression<Func<TModel, TProperty>> expression, 
     IEnumerable<SelectListItem> selectList, 
     IDictionary<string, object> htmlAttributes) 
    { 
     string name = ExpressionHelper.GetExpressionText(expression); 

     TagBuilder selectTag = new TagBuilder("select"); 
     selectTag.MergeAttributes(htmlAttributes); 
     selectTag.MergeAttribute("id", name, true); 
     selectTag.MergeAttribute("name", name, true); 
     foreach (SelectListItem item in selectList) 
     { 
      TagBuilder optionTag = new TagBuilder("option"); 
      optionTag.MergeAttribute("value", item.Value); 
      if (item.Selected) optionTag.MergeAttribute("selected", "selected"); 
      optionTag.InnerHtml = item.Text; 
      selectTag.InnerHtml += optionTag.ToString(); 
     } 

     return new MvcHtmlString(selectTag.ToString()); 
    } 
3

实际上,如果您查看MVC源代码,则默认情况下会将此行为烘焙到DropDownListFor中(搜索allowMultiple:false)。该解决方案是使用ListBoxFor代替(你会看到,以及在MVC源代码的AllowMultiple:true),这使得很多的意义,因为HTML明智的,既渲染

<select ...> 
    <option ...> 
    <option ...> 
    ... 
</select> 

你不必就如上面这个答案提出的模型使用不同的属性,我简单地切换而不是ListBoxFor得到了这个工作(CSS需要从那里):

@Html.ListBoxFor(model => model.SelectedCategories, 
    new MultiSelectList(Model.Categories, Model.SelectedCategories), 
    new { multiple = "multiple" }) 

工程就像一个魅力,甚至与POST和重新显示错误视图。

0

你可以去到“项”的值与此

<HttpPost()> _ 
    Function Edit(ByVal crm_cliente As crm_cliente, ByVal form As FormCollection) As ActionResult 
     If ModelState.IsValid Then 
      Dim items As String 
      crm_cliente.usuario_modifico = "ejmorales" 
      crm_cliente.fecha_modifico = Date.Now 
      items = form("items") 

,将让你选择的项目作为字符串单独用逗号(,)