views:

34

answers:

2

Hi guys,

Learning MVC and having major trouble over the last two days trying to bind data from a database to a dropdownlist in MVC. I'm currently following the nerddinner tutorial. I have followed it exactly and somehow still ended up with this error.

The ViewData item that has the key 'Dinner.Country' is of type 'System.String' but must be of type 'IEnumerable'.

I understand this is a lot of code to look at but if anyone feels so inclined to have a look over it - I'd be very grateful.

Here is my code:

DinnerFormViewModel.cs

 public class DinnerFormViewModel
    {
        private static string[] _countries = new[] {
            "USA",
            "UK",
            "IRL",
            "SA"
        };

        //Properties
        public Dinner Dinner { get; private set; }
        public SelectList Countries { get; private set; }

        //Constructor
        public DinnerFormViewModel(Dinner dinner)
        {
            Dinner = dinner;

            Countries = new SelectList(_countries, dinner.Country);
        }

DinnersController.cs

//
        //GET: /Dinners/Edit/2

        //[Authorize]
        public ActionResult Edit(int id)
        {
            Dinner dinner = dinnerrepository.GetDinner(id);

            //var countries = new[] {
              //  "USA", "Afganistan", "UK", "Ireland"};

            //ViewData["countries"] = new SelectList(countries, dinner.Country);

            return View(new DinnerFormViewModel(dinner));
        }

        //
        //POST: /Dinners/Edit/2

        [HttpPost]
        public ActionResult Edit(int id, FormCollection formvalues)
        {
            //Retrieve Existing Dinner
            Dinner dinner = dinnerrepository.GetDinner(id);

            //Update dinner with form posted values
            //dinner.Title = Request.Form["Title"];
            //dinner.Description = Request.Form["Description"];
            //dinner.EventDate = DateTime.Parse(Request.Form["EventDate"]);
            //dinner.Address = Request.Form["Address"];
            //dinner.Country = Request.Form["Country"];
            //dinner.ContactPhone = Request.Form["ContactPhone"];

            if (TryUpdateModel(dinner))
            {
                //Persist changes back to database
                dinnerrepository.Save();
                //Perform HTTP redirect to details page for the saved dinner
                return RedirectToAction("Details", new { id = dinner.DinnerID });
            }

            //var countries = new[] {
              //  "USA", "Afganistan", "UK", "Ireland"};

            //ViewData["countries"] = new SelectList(countries, dinner.Country);

            return View(new DinnerFormViewModel(dinner));
        }

And here is the snippet from the View that is causing me problems - Edit.aspx

<div class="editor-field">
                <%: Html.DropDownListFor(m => m.Dinner.Country, ViewData["countries"] as SelectList)%>
                <%: Html.ValidationMessageFor(m => m.Dinner.Country, "*")%>
            </div>

Also, I have bits of code commented out, these are from earlier in the tutorial and can be ignored. Also, for anyone who can actually understand what the stack trace, here it is:

InvalidOperationException: The ViewData item that has the key 'Dinner.Country' is of type 'System.String' but must be of type 'IEnumerable<SelectListItem>'.]
   System.Web.Mvc.Html.SelectExtensions.GetSelectData(HtmlHelper htmlHelper, String name) +458
   System.Web.Mvc.Html.SelectExtensions.SelectInternal(HtmlHelper htmlHelper, String optionLabel, String name, IEnumerable`1 selectList, Boolean allowMultiple, IDictionary`2 htmlAttributes) +321
   System.Web.Mvc.Html.SelectExtensions.DropDownListHelper(HtmlHelper htmlHelper, String expression, IEnumerable`1 selectList, String optionLabel, IDictionary`2 htmlAttributes) +48
   System.Web.Mvc.Html.SelectExtensions.DropDownListFor(HtmlHelper`1 htmlHelper, Expression`1 expression, IEnumerable`1 selectList, String optionLabel, IDictionary`2 htmlAttributes) +115
   System.Web.Mvc.Html.SelectExtensions.DropDownListFor(HtmlHelper`1 htmlHelper, Expression`1 expression, IEnumerable`1 selectList) +87
   ASP.views_dinners_edit_aspx.__RenderContent2(HtmlTextWriter __w, Control parameterContainer) in c:\Users\TaraW\Documents\Visual Studio 2010\Projects\NerdDinner\NerdDinner\Views\Dinners\Edit.aspx:52
   System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +109
   System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +8
   System.Web.UI.Control.Render(HtmlTextWriter writer) +10
   System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +100
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
   ASP.views_shared_site_master.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in c:\Users\TaraW\Documents\Visual Studio 2010\Projects\NerdDinner\NerdDinner\Views\Shared\Site.Master:26
   System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +109
   System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +8
   System.Web.UI.Control.Render(HtmlTextWriter writer) +10
   System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +100
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
   System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +208
   System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +8
   System.Web.UI.Page.Render(HtmlTextWriter writer) +29
   System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer) +56
   System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +100
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3060
A: 

Change this:

<%: Html.DropDownListFor(m => m.Dinner.Country, ViewData["countries"] as SelectList)%>

to:

<%: Html.DropDownListFor(m => m.Dinner.Country, Model.Countries.Items)%>
Martin
@Martin, Thanks for your reply but no luck with that.
TaraWalsh
A: 

First you need to define a property which will hold the selected country id on your view model:

public class DinnerFormViewModel
{
    private static string[] _countries = new[] {
        "USA",
        "UK",
        "IRL",
        "SA"
    };

    //Properties
    public Dinner Dinner { get; private set; }

    // will hold the selected country value
    public string SelectedCountry { get; set; }
    public SelectList Countries { get; private set; }

    //Constructor
    public DinnerFormViewModel(Dinner dinner)
    {
        Dinner = dinner;
        Countries = new SelectList(_countries, dinner.Country);
    }
}

And then:

<%: Html.DropDownListFor(m => m.SelectedCountry, Model.Countries) %>
Darin Dimitrov