[Asp.net-mvc] Warum ist ListBox nicht für die Auswahl von Elementen, sondern für ListBox?


Answers

Ich bin selbst über dieses Problem gestolpert, schließlich wurde mir klar, dass das Problem eine Namenskonvention war.

Sie können die ViewBag- oder ViewData-Eigenschaft, die SelectList oder MultiSelectList enthält, nicht mit demselben Namen benennen wie Ihr Eigenschaftsmodell, das die ausgewählten Elemente enthält. Zumindest nicht, wenn Sie den Helper ListBoxFor oder DropDownListFor verwenden.

Hier ist ein Beispiel:

    public class Person
    {
          public List<int> Cars { get; set; }
    }

    [HttpGet]
    public ActionResult Create()
    {
          //wont work
          ViewBag.Cars = new SelectList(carsList, "CarId", "Name"); 

          //will work due to different name than the property.
          ViewBag.CarsList = new SelectList(carsList, "CarId", "Name"); 

          return View();
    }

    //View
    @Html.ListBoxFor(model => model.Cars, ViewBag.CarsList as SelectList)

Ich bin sicher, es gibt viele andere Möglichkeiten, dies zu tun, aber es löste mein Problem, hoffe, es wird jemandem helfen!

Question

Ich habe folgenden Code aus meiner Sicht:

<%= Html.ListBoxFor(c => c.Project.Categories,
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

<%= Html.ListBox("MultiSelectList", 
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

Der einzige Unterschied besteht darin, dass der erste Helper stark typisiert ist (ListBoxFor) und die ausgewählten Elemente (1,2) nicht angezeigt werden, obwohl die Elemente in der Liste usw. erscheinen. Das einfachere ListBox funktioniert wie erwartet.

Ich vermisse hier offensichtlich etwas. Ich kann den zweiten Ansatz verwenden, aber das nervt mich wirklich und ich würde es gerne herausfinden.

Als Referenz ist mein Modell:

public class ProjectEditModel
{
    public Project Project { get; set; }
    public IEnumerable<Project> Projects { get; set; }
    public IEnumerable<Client> Clients { get; set; }
    public IEnumerable<Category> Categories { get; set; }
    public IEnumerable<Tag> Tags { get; set; }
    public ProjectSlide SelectedSlide { get; set; }
}

Aktualisieren

Ich habe gerade den ListBox-Namen in Project.Categories (passend zu meinem Modell) geändert und es fehlt jetzt die Auswahl des Elements.

<%= Html.ListBox("Project.Categories",
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

Ich verstehe offensichtlich nicht die Magie, die hier passiert.

Update 2

Ok, das ist reine Namensgebung, zum Beispiel funktioniert das ...

<%= Html.ListBox("Project_Tags",
new MultiSelectList(Model.Tags, "Id", "Name", Model.Project.Tags.Select(t => t.Id)))%>

... weil der Feldname Project_Tags und nicht Project.Tags ist, funktioniert alles andere als Tags oder Project.Tags. Ich verstehe nicht, warum dies ein Problem verursachen würde (abgesehen davon, dass es mit dem Namen der Entität übereinstimmt), und ich bin nicht gut genug, um darin nachforschen und es herausfinden zu können.




Ich bin auch mit genau diesem gleichen Problem stecken geblieben und habe das gleiche Problem mit ListBox und ListBoxFor festgestellt.

Egal, was ich mache, ich kann keine Auswahlen auf der ListBoxFor auftreten. Wenn ich in die ListBox wechsle und ihr etwas anderes als den Eigenschaftsnamen der Daten nenne, an die ich mich verbinde, erfolgt die Auswahl.

Aber weil ich nicht ListBoxFor verwende und die Daten beispielsweise in einer Modellklasse (Model.Departments) sitzen, bekomme ich auf dem Weg zurück zu meinem Controller keine Modellbindung, und daher ist die Eigenschaft null.

EDIT Ich habe eine Lösung gefunden, die von jemand anderem hier gepostet wurde; Herausforderungen beim Auswählen von Werten in ListBoxFor




Html.ListboxFor und Html.Listbox funktionieren hervorragend, wenn Sie das Listenfeld NICHT an seine Datenquelle binden. Ich nehme an, der Verwendungszweck ist dies:

// Model
public class ListBoxEditModel
{
    public IEnumerable<Category> Categories { get; set; }
    public IEnumerable<Category> SelectedCategories { get; set; }
}    

In der Ansicht:

@Html.ListBoxFor(m => m.SelectedCategories,
                 new MultiSelectList(Model.Categories, "Id", "Name"))
// or, equivalently
@Html.ListBox("SelectedCategories" ,
                 new MultiSelectList(Model.Categories, "Id", "Name"))

Beachten Sie, dass Sie in diesem Fall nicht explizit angeben müssen, welche Werte in der MultiSelectList ausgewählt sind - das Modell, an das Sie binden, hat Vorrang, selbst wenn Sie dies tun!




Versuche dies

<%= Html.ListBoxFor(c => c.Project.Categories,
    new MultiSelectList(
        Model.Categories
        ,"Id"
        ,"Name"
        ,Model.Project.Tags.Select(
        x => new SelectListItem()
            {
            Selected = true,
            Text = x.TEXT,
            Value = x.ID.ToString()
            }).ToList())

       )
)%>



Die richtige Antwort ist, dass es nicht sehr gut funktioniert. Daher lese ich den MVC-Code. Was Sie tun müssen, ist IConvertible zu implementieren und einen TypeConverter zu erstellen.

Also hatte ich in meinem Fall eine Country Klasse, so dass die Leute aus einer Liste von Ländern wählen konnten. Keine Freude bei der Auswahl. Ich habe erwartet, dass ein Objekt den Vergleich auf den selectedItems mit den listitems aber nein, so funktioniert es nicht. Trotz der Tatsache, dass MultiListItem die ausgewählten Elemente korrekt MultiListItem und MultiListItem , wird sie in dem Moment, in dem sie an Ihr Modell gebunden ist, darauf überprüft, ob die String-Repräsentation Ihrer Objektinstanz mit der Zeichenfolge "value" (oder dem fehlenden Namen) "value" Liste von Elementen in der SelectItemList .

Implementieren Sie daher IConvertible und geben Sie den Zeichenfolgenwert aus ToString der mit dem Wert in der SelectItemList . zB in meinem Fall wurde SelectItem in die SelectItem Value Eigenschaft serialisiert, so ToString IConvertible ich in ToString IConvertible habe. Jetzt wird alles richtig gewählt.

Ich werde darauf hinweisen, dass der TypeConverter auf dem Weg in verwendet wird. Dies ist die Umkehrung. Dieser Countrycode kommt zurück und "EN" muss in die Country konvertiert werden. TypeConverter kam der TypeConverter ins TypeConverter . Es ging auch um die Zeit, als mir klar wurde, wie schwierig dieser Ansatz ist.

ps so auf Ihrer Category Klasse müssen Sie IConvertible implementieren. Wenn es aus dem Entitätsframework wie meiner Firma ist, dann musst du die partielle Klasse verwenden, um IConvertible zu implementieren und ToString implementieren und es mit einem TypeConverter zu TypeConverter du auch geschrieben hast.




Obwohl dies keine Antwort auf Ihre Hauptfrage ist, sollte angemerkt werden, dass wenn MVC Namen erzeugt, es so etwas wie Project.Tags in Project_Tags umwandelt und Perioden durch Unterstriche ersetzt.

Der Grund dafür ist, dass ein Punkt in einer Element-ID wie ein Element namens Projekt mit einer Klasse von Tags zu CSS aussehen würde. Klar eine schlechte Sache, daher unterstreicht die Übersetzung, um Verhalten vorhersehbar zu halten.

In deinem ersten Beispiel

<%= Html.ListBoxFor(c => c.Project.Categories,
    new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

Die Listbox versucht, an Model.Project.Categories für Ihr stark typisiertes Modell zu binden, das der Seite zur Verfügung gestellt wurde (in der Lambda-Notation). Ich bin mir nicht sicher, was der zweite Parameter in der ListBoxFor tut.

Was ist das Modell, das an die Seite übergeben wird?




Sie können auch versuchen, ModelState für c.Project.Categories im Controller zu löschen:

[HttpPost]
public ActionResult Index(ModelType model)
{
    ModelState.Remove("Project.Categories");
    return View("Index", model);
}

Und nutze die nächste Konstruktion:

<%= Html.ListBoxFor(c => c.Project.Categories,
        new MultiSelectList(Model.Categories, "Id", "Name"))%>

Wo c.Project.Categories ist IEnumerable<int> .

Entschuldigung für mein Englisch. Viel Glück!