Domanda Sfide con la selezione dei valori in ListBoxFor


Recentemente, lavorando alla mia prima app web ASP.Net MVC2, ho riscontrato alcuni problemi quando avevo bisogno di selezionare più valori in una casella di riepilogo. Ho lavorato intorno ad esso con alcuni jQuery, ma sono andato avanti e ho messo insieme un codice molto semplice da dimostrare. Sto utilizzando EF per il modello, con due entità: Clienti e HelpDeskCalls:

controller:

 public ActionResult Edit(int id)
    {
        Customer currCustomer = ctx.Customers.Include("HelpDeskCalls").Where(c => c.ID == id).FirstOrDefault();
        List<HelpDeskCall> currCustCalls = (ctx.HelpDeskCalls.Where(h => h.CustomerID == id)).ToList();
        List<SelectListItem> currSelectItems = new List<SelectListItem>();
        List<String> selectedValues = new List<string>();
        foreach (HelpDeskCall currCall in currCustCalls)
        {
            bool isSelected = (currCall.ID % 2 == 0) ? true : false;
            //Just select the IDs which are even numbers...
            currSelectItems.Add(new SelectListItem() { Selected = isSelected, Text = currCall.CallTitle, Value = currCall.ID.ToString() });
            //add the selected values into a separate list as well...
            if (isSelected)
            {
                selectedValues.Add(currCall.ID.ToString());
            }
        }
        ViewData["currCalls"] = (IEnumerable<SelectListItem>) currSelectItems;
        ViewData["currSelected"] = (IEnumerable<String>) selectedValues;
        return View("Edit", currCustomer);
    }

Vista:

<div class="editor-field">
    <%: Html.ListBoxFor(model => model.HelpDeskCalls, new MultiSelectList(Model.HelpDeskCalls, "ID", "CallTitle", (IEnumerable) ViewData["currSelected"]), new { size = "12" })%>       
    <%: Html.ListBoxFor(model => model.HelpDeskCalls, ViewData["currCalls"] as IEnumerable<SelectListItem>, new { size = "12"}) %>
    <%: Html.ListBox("Model.HelpDeskCalls", new MultiSelectList(Model.HelpDeskCalls, "ID", "CallTitle", (IEnumerable)ViewData["currSelected"]), new { size = "12"}) %>      
    <%: Html.ValidationMessageFor(model => model.HelpDeskCalls) %>
</div>

Per questo esempio, sto selezionando HelpDeskCall.IDs che sono pari. Sto provando due diverse sintassi per ListBoxFor: One utilizza un IEnumerable di valori per le selezioni, uno utilizza un oggetto IEnumerable di SelectListItems. Per impostazione predefinita, quando eseguo questo codice, non vengono apportate selezioni a ListBoxFor, ma il ListBox non fortemente digitato seleziona correttamente.

Leggo questo post su ASP.Net e questo thread su SO, ma nessuna gioia. Infatti, se aggiungo l'override di ToString () alla mia classe HelpDeskCall (come suggerito nel thread ASP.net) tutti i valori sono selezionati, il che non è corretto neanche.

Se qualcuno potesse far luce su come dovrebbe funzionare (e cosa mi manca o cosa non va), questo neofita sarebbe molto grato.


44
2017-07-07 11:15


origine


risposte:


Ecco un esempio che illustra la versione fortemente tipizzata:

Modello:

public class MyViewModel
{
    public int[] SelectedItemIds { get; set; }
    public MultiSelectList Items { get; set; }
}

controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        // Preselect items with id 1 and 3
        var selectedItemIds = new[] { 1, 3 };

        var model = new MyViewModel
        {
            Items = new MultiSelectList(
                new[] 
                {
                    // TODO: Fetch from your repository
                    new { Id = 1, Name = "item 1" },
                    new { Id = 2, Name = "item 2" },
                    new { Id = 3, Name = "item 3" },
                }, 
                "Id", 
                "Name", 
                selectedItemIds
            )
        };

        return View(model);
    }
}

Vista:

<%: Html.ListBoxFor(x => x.SelectedItemIds, Model.Items) %>

90
2017-07-07 14:58



Non so se questo comportamento è cambiato nell'RTM di MVC3 che sto usando, ma sembra che la selezione e l'associazione ora funzionino fuori dalla scatola. L'unico problema è che il modello dovrebbe contenere una proprietà con gli ID, in questo modo:

public class MyViewModel {
    public int[] ItemIDs { get; set; }
}

Quindi la seguente vista funzionerebbe bene, sia preselezionando i valori corretti che vincolando correttamente durante il post:

@Html.ListBoxFor(model => model.ItemIDs, (IEnumerable<SelectListItem>)(new[] { 
                                new SelectListItem() { Value = "1", Text = "1" }, 
                                new SelectListItem() { Value = "2", Text = "2" } 
                             }))

8
2018-01-19 14:21



Ho trovato una soluzione migliore. Modo usuale per preselezionare l'elenco selezionato:

@Html.ListBoxFor(
    model => model.Roles, 
    new MultiSelectList(db.Roles, "Id", "Name")
)
@Html.ValidationMessageFor(model => model.Roles)    

Non funziona .., mai nessuna opzione è selezionata, fino a quando:

public ActionResult Edit(int id)
{
    var user = db.Users.Find(id);
    // this is workaround for http://aspnet.codeplex.com/workitem/4932?ProjectName=aspnet
    ViewData["Roles"] = user.Roles.Select(r => r.Id);
    return View(user);
}

I ruoli selezionati devono essere memorizzati in ViewData, per aggirare un bug sgradevole.


2
2017-09-08 15:49