Search code examples
asp.net-mvc-viewmodel

ListBoxFor 'List' error needing to be a 'SelectedListItem'


Following https://www.codeproject.com/Articles/702890/MVC-Entity-Framework-and-Many-to-Many-Relation example, I have the next error when posting my Edit.cshtml:

"The ViewData item that has the key 'SelectedTelephoneCellulaires' is of type 'System.Collections.Generic.List' but must be of type 'IEnumerable'."

I searched online (of course!), but the two closest related problems-answers (Issues converting types to new selectitemlist && @Html.DropDownListFor not posting back to controller) did not bring any solution to my difficulty.

Here's a part of my ViewModel (on diet, for readability sake):

public partial class EmployeVM
{        
    public Employe Employe { get; set; } //Employe

    public IEnumerable<SelectListItem> AllTelephoneCellulaires { get; set; } //TelephoneCellulaire        
    private List<int> _selectedTelephoneCellulaires;
    public List<int> SelectedTelephoneCellulaires
    {
        get
        {
            if (_selectedTelephoneCellulaires == null)
            {
                _selectedTelephoneCellulaires = Employe.TelephoneCellulaire1.Select(m => m.IdTelephoneCellulaire).ToList();
            }
            return _selectedTelephoneCellulaires;
        }
        set { _selectedTelephoneCellulaires = value; }
    }
}

}

Some part of my EmployesController (on diet as well):

[HttpPost]
    [ValidateAntiForgeryToken]        
    public ActionResult Edit(EmployeVM employeView)
    {
        if (employeView == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }

        if (ModelState.IsValid)
        {
            var employeToUpdate = db.Employe
                .Include(e => e.TelephoneCellulaire1)
                [...]
                .First(e => e.IdEmploye == employeView.Employe.IdEmploye);

            if (TryUpdateModel(employeToUpdate, "Employe", new string[] { "NomEmploye", "PrenomEmploye", "IdTitre", "IdDepartement", "IdSuperviseur", "DateEmbauche", "DateDepart", "StatutEmploye", "IdEmployeur", "IdLocalisation", "Langue", "CarteAcces", "TelephoneCellulaire", "IdTelephoneBureau", "CarteAffaire", "EquipementInformatique", "AdresseCourriel", "GroupeSecurite", "AccesApplicatif", "CodeAlarme", "CleBatiment", "VehiculeCompagnie", "DateNaissance", "IsSuperviseur", "IsActif" }))
            {
                var newTelephoneCellulaires = db.TelephoneCellulaire.Where(m => employeView.SelectedTelephoneCellulaires.Contains(m.IdTelephoneCellulaire)).ToList();
                [...]

                var updatedTelephoneCellulaires = new HashSet<int>(employeView.SelectedTelephoneCellulaires);
                [...]

                foreach (TelephoneCellulaire telephone in db.TelephoneCellulaire)
                {
                    if (!updatedTelephoneCellulaires.Contains(telephone.IdTelephoneCellulaire))
                    {
                        employeToUpdate.TelephoneCellulaire1.Remove(telephone);
                    }
                    else
                    {
                        employeToUpdate.TelephoneCellulaire1.Add(telephone);
                    }
                }
                [...]

                db.Entry(employeToUpdate).State = EntityState.Modified;
                db.SaveChanges();
            }
            return RedirectToAction("Index");
        }

        if (!ModelState.IsValid)
        {
            foreach (var obj in ModelState.Values)
            {
                foreach (var error in obj.Errors)
                {
                    if (!string.IsNullOrEmpty(error.ErrorMessage))
                        System.Diagnostics.Debug.WriteLine("ERROR WHY = " + error.ErrorMessage);
                }
            }
        }

        return View(employeView);
    }

And finally, my Edit.cshtml (you guessed it - on diet...)

<div class="form-group">
        @Html.LabelFor(model => model.AllTelephoneCellulaires, "Téléphones cellulaires", htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">               
            @Html.ListBoxFor(m => m.SelectedTelephoneCellulaires, Model.AllTelephoneCellulaires)
        </div>
    </div>

Both precedent answers addressed the fact that "Model.AllTelephoneCellulaires" would cause the error, but not the "m.SelectedTelephoneCellulaires"

The funniest thing is that I was able, a while ago, to edit an employe without any problem, but when I tried to edit another one (both without touching the 'TelephoneCellulaire' input), bang! Here came the error.

I just don't understand why I get this error? Why my SelectedThing would need to be of type "SelectListItem"?? And how I can fix it??? If someone is capable to help me, I will be forever obliged to you. Right now, I'm hidden crying under my desk, sucking my thumb in foetal position...


Solution

  • From the code you provided, I am very positive that you are getting this error because you are not passing a valid SelectListItem collection to the ListBoxFor helper method.

    I think Model.AllTelephoneCellulaires is currently returning NULL where it should be a valid collection. One solution is to initialize this to an empty list in your GET action method or your view model classes constructor.

    public partial class EmployeVM
    {
        // Your other properties goes here.
    
        public IEnumerable<SelectListItem> AllTelephoneCellulaires { get; set; }
        public EmployeVM()
        {
            AllTelephoneCellulaires = new List<SelectListItem>();
        }
    }