2010-09-17 9 views
22

Auswahl weiß, dass ich anderen diese Frage gestellt haben, aber ich bin durch diese total verwirrt:ASP.NET MVC MultiSelectList mit ausgewählten Werte nicht richtig

Dies zeigt das Drop-Down ohne ausgewählte Werte:

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

Dies zeigt die Drop-Down mit den Werten, die ich in (Model.items) bin vorbei ausgewählt richtig, was ich erwarten würde:

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

Aber das Problem ist, dass dieser Punkt jetzt „einige Namen Thingelse "wenn ich POST. Ich weiß, ich kann das hacken, aber was geht?

+1

Statt mehrere auf Html der Einstellung .DropDownList können Sie Html.ListBoxFor verwenden. Da Html.DropDownList nur eines der auszuwählenden Elemente festlegen wird. –

+0

@NikitaIgnatov Danke. Dein Kommentar hilft mir wirklich sehr. – gfan

Antwort

18

Das Problem, das Sie haben, verwendet Model.Items als Parameter. Der Code

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

funktioniert nicht wie erwartet. Es funktioniert, weil der Name des Dropdown-Menüs "Elemente" ist. Das liegt daran, dass ein Formularparameter mit der Bezeichnung "Elemente" zu Ihrer Aktion zurückgeschickt wurde. Dieser Parameter wird im ViewState der Aktion gespeichert (nicht mit ViewData verwechseln). Die Html.DropdownList() erkennt, dass es einen ViewState-Parameter gibt, der denselben Namen wie Ihr Dropdown-Name hat und diesen ViewState-Parameter verwendet, um die ausgewählten Werte zu berechnen. Es ignoriert vollständig die Model.items, die Sie übergeben haben.

Wenn jemand die Logik erklären kann, das Standardverhalten nicht zu überschreiben, dann würde ich es gerne hören.

Also, das ist dein erstes Problem. Um alles zu umgehen, müssen Sie das Dropdown-Menü in etwas anderes umbenennen - genau wie in Ihrem zweiten Beispiel. Jetzt kommt Ihr zweites Problem ins Spiel: Die Liste ausgewählter Objekte muss eine Sammlung einfacher Objekte sein (ich denke, es muss tatsächlich ein IEnumerable sein, aber ich bin mir nicht 100% sicher).

Die DropDownList() -Methode versucht, diese ausgewählten Werte mit dem Wert in Ihrer AvailableItems-Auflistung abzugleichen. Wenn dies nicht möglich ist, wird versucht, den Text abzugleichen.

dies Also, versuchen Sie, um zu sehen, ob es

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

Viel Glück

+3

Dies funktioniert nicht, wenn Sie mehrere Elemente ausgewählt haben. Es wählt einfach das zuerst ausgewählte aus und ignoriert den Rest. Sehe Darin's Antwort. – Castrohenge

+0

FINALY eine funktionierende Lösung! Ich habe meinen ganzen Morgen an diesem Mist verloren, danke;) –

47

Zu wenig Kontext in Ihrer Frage zur Verfügung gestellt, aber ich werde versuchen, ein voll funktionierendes Beispiel zu zeigen:

Modell:

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

Controller:

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

Ausblick:

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

Beachten Sie, dass die Html.ListBoxFor besser angepasst ist, wenn Sie eine Mehrfachauswahl generieren möchten. Offensichtlich sollte die AvailableItems-Eigenschaft aus einem Repository abgerufen werden.

+0

Danke Darin Dimitrov für Ihre Hilfe. Sie sind überall .. :) – yusuf

+0

Qualität Antwort. – radbyx

+0

Hat sich in MVC5 etwas geändert, weil diese genaue Antwort nicht mehr funktioniert? – YesMan85

5

arbeitet Ich hatte das gleiche Problem, ich meine eigene Erweiterung Methode verwendet, um die HTML-und Problem

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()); 
    } 
gelöst zu erzeugen
3

Eigentlich, wenn Sie sich den MVC-Quellcode ansehen, wird dieses Verhalten standardmäßig in DropDownListFor eingebettet (Suche nach allowMultiple: false). Die Lösung ist ListBoxFor zu verwenden, anstatt (Sie, dass auch in der MVC-Quellcode sehen, allowMultiple: true), die sehr viel Sinn als HTML klug macht, machen beide zu

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

Sie haben noch unterschiedliche Eigenschaften auf dem Modell zu verwenden, wie in den Antworten über diesem vorgeschlagen, ich diese Arbeit bekam durch einfaches Umschalten statt ListBoxFor (CSS nimmt es von dort):

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

wirkt wie ein Zauber, auch mit POST und Erneutes Anzeigen der Sicht auf Fehler.

0

Sie auf die auf den Wert von „items“ gehen kann mit diesem

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

, dass Sie die ausgewählten Elemente als String getrennt mit Komma erhalten wird (,)

Verwandte Themen