Search code examples
c#asp.net-mvchtml.dropdownlistforselectlistitem

C# Why can not System.String converted while using "DropDownListFor"?


Firstly, my point is to create a project. Users will be able to choose a parent project of this project from dropdownlist. When users choose a parent project of the project, this should be saved to the database(db) as a parent project property.

My error Message is below.

[System.InvalidOperationException] = {"The parameter conversion from type 'System.String' to type 'ProjectName.Models.Project' failed because no type converter can convert between these types."}

my ProjectsController Actions:

    //GET
    public ActionResult Create()
    {

        var projectList = db.Projects.ToList().Select(
            c => new SelectListItem
                {
                    Selected = false,
                    Text = c.projectName,
                    Value = c.projectID.ToString()
                }
            ).ToList();
        ViewData["ProjectList"] = projectList;
        return View();
    }

    //
    // POST: /Project/Create

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(Project project)
    {
        var projectList = db.Projects.ToList().Select(
            c => new SelectListItem
                {
                    Selected = false,
                    Text = c.projectName,
                    Value = c.projectID.ToString()
                }
            ).ToList();
        ViewData["ProjectList"] = projectList;

        if (ModelState.IsValid)
        {
            db.Projects.Add(project);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(project);
    }

my Project class :

 public class Project{

    public int projectID { get; set; }


    public string projectName { get; set; }


    public string descriptionProject { get; set; }

    public Project parentProject { get; set; }
 }

my Context class:

public class DBContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Project> Projects { get; set; }
    public DbSet<Issue> Issues { get; set; }
}

and finally my view :

        @model ProjectName.Models.Project
        ....

        <div class="form-group">
            @Html.LabelFor(model => model.parentProject, new { @class = "col-lg-2 control-label" })

            <div class="col-lg-10">
                <p>@Html.DropDownListFor(model => model.projectID, (IEnumerable<SelectListItem>)ViewData["ProjectList"], " --Select Parent Project--")</p>
                @Html.ValidationMessageFor(model => model.parentProject)
            </div>
        </div>

I am waiting your responses. Thanks in advance. By the way, I am using mvc 5.2, visual studio 2013 update 2.


Solution

  • In your controller: add the list of select items to your view model instead of viewBag or view data since they are not strongly typed.It's a good practice to do so. do not convert in the HtmlHelper.

    By the way, here is a generic method I created to populate dropdown lists in one of my projects.You can even append static values like All or Nothing.

        public IEnumerable<SelectListItem> GetSelection<T>(IEnumerable<T> data,
           Func<T, string> name = null,
           Func<T, string> key = null,
           string defaultValue = "0",
           bool showAllValue = true,
           bool showNothing = false)
        {
            var selectItemList = new List<SelectListItem>();
            if (showAllValue)
            {
                selectItemList.Add(new SelectListItem { Text = "Choose All", Value = 0 });
            }
            if (showNothing)
            {
                selectItemList.Add(new SelectListItem { Text = "Nothing Selected", Value = -1 });
            }
    
            selectItemList.AddRange(data.Select(item => key != null ? (name != null ? new SelectListItem
            {
                Text = name(item),
                Value = key(item)
            } : null) : null));
    
            //default selection
            var defaultItem = selectItemList.FirstOrDefault(x => x.Value == defaultValue);
            if (defaultItem != null)
            {
                defaultItem.Selected = true;
            }
            else
            {
                var firstItem = selectItemList.FirstOrDefault();
                if (firstItem != null) firstItem.Selected = true;
            }
            return selectItemList;
        }
    

    You can call it like this:

    public IEnumerable<SelectListItem> GetClientSelectionList(string defaultClient = "0", bool showAllValue = false)
        {
            return this.GetSelection(data: _clientsManager.GetClients(),
                                            name: s => s.Client_Name,
                                            key: s => s.Client_ID.ToString(CultureInfo.InvariantCulture),
                                            defaultValue: defaultClient,
                                            showAllValue: showAllValue
                );
        }