2010-09-17 85 views
22

Sé que otros han hecho esta pregunta, pero estoy totalmente confundido por esto:ASP.NET MVC MultiSelectList con los valores seleccionados no seleccionar adecuadamente

Esto muestra el menú desplegable sin valores seleccionados:

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

esto muestra el menú desplegable con los valores que estoy pasando en (Model.items) seleccionados adecuadamente como lo que cabe esperar:

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

Pero el problema es que este artículo se llama ahora "algunos thingelse "cuando PUBLICO. Sé que puedo hackear esto pero, ¿qué ocurre?

+1

En lugar de establecer múltiples en HTML .DropDownList, puede usar Html.ListBoxFor. Dado que Html.DropDownList solo configurará uno de los elementos que se seleccionarán. –

+0

@NikitaIgnatov Gracias. tu comentario realmente me ayuda mucho. – gfan

Respuesta

18

El problema que tiene es el uso de Model.Items como parámetro. El código

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

no está funcionando como usted espera. Está funcionando porque el nombre del menú desplegable es "artículos". Eso se debe a que había un formulario llamado "artículos" que se envió a su acción. Ese parámetro se almacena en el ViewState de la acción (no confundas con ViewData). El Html.DropdownList() ve que hay un parámetro de ViewState llamado igual al nombre de su menú desplegable y usa ese param ViewState para calcular los valores seleccionados. Ignora por completo los elementos Model.items que pasó.

Si alguien puede explicar la lógica de no poder anular el comportamiento predeterminado, me encantaría escucharlo.

Entonces, ese es su primer problema. Para evitarlo, todo lo que tienes que hacer es cambiar el nombre del menú desplegable a otra cosa, exactamente como lo hiciste en tu segundo ejemplo. Ahora su segundo problema entra en juego: la lista de elementos seleccionados debe ser una colección de objetos simples (creo que realmente necesita ser un IEnumerable pero no estoy 100% seguro).

El método DropDownList() intentará hacer coincidir los valores seleccionados con el valor en su colección AvailableItems. Si no puede hacer eso, intentará hacer coincidir el Texto.

lo tanto, intentar esto para ver si funciona

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

Buena suerte

+3

Esto no funciona si ha seleccionado varios elementos. Simplemente selecciona el primero que seleccionó e ignora el resto. Vea la respuesta de Darin. – Castrohenge

+0

¡FINALY una solución de trabajo! Perdí toda mi mañana en esta mierda, gracias;) –

47

Demasiado poco de contexto proporciona en su pregunta, pero voy a tratar de mostrar un ejemplo de trabajo completo:

Modelo:

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" }, 
      }; 
     } 
    } 
} 

controlador:

[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); 
    } 
} 

Vista:

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

Observe que el Html.ListBoxFor es más adecuado si desea generar una selección múltiple. Obviamente, la propiedad AvailableItems debe buscarse en un repositorio.

+0

Darin Dimitrov gracias por tu ayuda ... Estás en todas partes ... :) – yusuf

+0

Respuesta de calidad. – radbyx

+0

Algo cambió en MVC5 porque esta respuesta exacta ya no funciona. – YesMan85

5

que tenía el mismo problema, he usado mi propio método de extensión para generar el html y problema resuelto

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

En realidad, si nos fijamos en el código fuente de MVC, este comportamiento se integra en DropDownListFor de forma predeterminada (busque allowMultiple: false). La solución es utilizar ListBoxFor lugar (se verá que así en el código fuente de MVC, allowMultiple: true), que tiene mucho sentido como HTML sabia, tanto rendir a

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

Usted no tiene utilizar diferentes propiedades en el modelo como se sugiere en las respuestas anteriores éste, conseguí este trabajo simplemente cambiando a ListBoxFor lugar (CSS lo toma de allí):

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

funciona como un encanto, incluso con POST y volver a mostrar la vista en caso de error.

0

Usted puede ir a la que el valor de "elementos" con este

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

que les permite conocer los elementos seleccionados como una cadena separada por comas (,)

Cuestiones relacionadas