melomg
melomg

Reputation: 748

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.

Upvotes: 0

Views: 824

Answers (1)

Oualid KTATA
Oualid KTATA

Reputation: 1116

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

Upvotes: 1

Related Questions