Problem Solved – DropDownList and ViewData

One of the requirements of our application is to simplify data entry and minimize errors.  For example, member shirt size should be recorded for when they get an award of a shirt for run milestones.  These sizes should match standards.  Run status should be selected from a dictionary. I don’t really want to keep these dictionaries in the database, so my challenge was to:

  • Build a drop down list of allowed values for create functions.
  • Use the drop down list in edit functions but set the selected item to whatever is currently in the database.

Both these took some time to work out.  If you search on ViewData, you will find endless people asking questions because they are having problems.  It took me a while to figure out how to use ViewData, and I think the key for me was understanding that you can put almost anything in ViewData and it will behave like an object that you can extract from.  Naming the ViewData correctly is also important.

Challenge 1:  Getting ViewData to work

You know you have a problem if you get debugging messages saying something like one type cannot be converted to another.  So you have to get the types in your ViewData to match the types expected where you will use them.  Duh, seems obvious to say it now, but until you have made a mistake or two even the explanations on the Internet don’t make much sense.  Here is a typical case, let’s look at the HMTL first:

         <tr>
        <td>Run Status</td>
        <td><%= Html.DropDownList("RunStatus") %></td>
        </tr>

So I need to populate my drop down list with a stanard list of selectable items.  The code in the controller to do this is:

            List<SelectListItem> rs = new List<SelectListItem>();
           rs.Add(new SelectListItem() { Text = "Hare(s) Needed", Value = "Hare(s) Needed" });
           rs.Add(new SelectListItem() { Text = "Run Claimed", Value = "Run Claimed" });
           rs.Add(new SelectListItem() { Text = "Confirmed", Value = "Confirmed" });
           rs.Add(new SelectListItem() { Text = "Completed", Value = "Completed" });
           rs[0].Selected = true;
           ViewData["RunStatus"] = rs;

Using SelectListItem is key here, an array of these is what the DropDownList expects.  You will find a ton of articles on the Internet explaining this issue (but not always clearly).

Challenge 2:  Setting the Selected Value in the DropDownList to Match Database Value

When editing the run, I want to take whatever is already in the database and make that the selected item in the drop down list.  This is so the user doesn’t make an error when editing a run by accidentally setting the value to whatever is first on the list.  So here is the solution I figured out:

             Run r = rr.GetRun(id);
            int sel = 0;
            string val = r.RunStatus;
            
            switch (val)
            {
                case "Hare(s) Needed" : sel = 0; break;
                case "Run Claimed": sel = 1; break;
                case "Confirmed": sel = 2; break;
                case "Completed": sel = 3; break;
                default: sel = 0; break;
            }
            
            if (r == null) return View("NotFound");
            else
            {
                // List of Run Status
                List<SelectListItem> rs = new List<SelectListItem>();
                rs.Add(new SelectListItem() { Text = "Hare(s) Needed", Value = "Hare(s) Needed" });
                rs.Add(new SelectListItem() { Text = "Run Claimed", Value="Run Claimed" });
                rs.Add(new SelectListItem() { Text = "Confirmed", Value="Confirmed" });
                rs.Add(new SelectListItem() { Text = "Completed", Value="Completed" });
                rs[sel].Selected = true;
                ViewData["RunStatus"] = rs;
 
                return View("Edit", r);
            }