views:

25333

answers:

6

Have just started playing with ASP.NET MVC and have stumbled over the following situation. It feels a lot like a bug but if its not, an explanation would be appreciated :)

The View contains pretty basic stuff

<%=Html.DropDownList("MyList", ViewData["MyListItems"] as SelectList)%>
<%=Html.TextBox("MyTextBox")%>

When not using a model, the value and selected item are set as expected:

//works fine
public ActionResult MyAction(){
  ViewData["MyListItems"] = new SelectList(items, "Value", "Text"); //items is an ienumerable of {Value="XXX", Text="YYY"}

  ViewData["MyList"] = "XXX"; //set the selected item to be the one with value 'XXX'
  ViewData["MyTextBox"] = "ABC"; //sets textbox value to 'ABC'

  return View();
}

But when trying to load via a model, the textbox has the value set as expected, but the dropdown doesnt get a selected item set.

//doesnt work
public ActionResult MyAction(){
  ViewData["MyListItems"] = new SelectList(items, "Value", "Text"); //items is an ienumerable of {Value="XXX", Text="YYY"}

  var model = new {
    MyList = "XXX", //set the selected item to be the one with value 'XXX'
    MyTextBox = "ABC" //sets textbox value to 'ABC'
  }

  return View(model);
}

Any ideas? My current thoughts on it are that perhaps when using a model, we're restricted to setting the selected item on the SelectList constructor instead of using the viewdata (which works fine) and passing the selectlist in with the model - which would have the benefit of cleaning the code up a little - I'm just wondering why this method doesnt work....

Many thanks for any suggestions

+3  A: 

After a bunch of hemming and hawing it boils down to the following line of code

if (ViewData.ModelState.TryGetValue(key, out modelState))

which means MVC is trying to resolve the value by only looking at the ViewData Dictionary<> object and not traversing down into the ViewData.Model object.

Whether that's a bug, limitation or design decision I'm not sure. However, you can fix it the following way:

<%= Html.TextBox("MyTextBox", ViewData.Model.MyTextBox) %>
Todd Smith
Thanks for the suggestion Todd,As I mentioned in the post, if using a model you can get around it with:var model{ MyList = new SelectList(items, "Value", "Text", selected_value) }and just:<%=Html.DropDownList("MyList")%>
chrisb
Its mainly just the behaviour that was puzzling me - least you've given me a start now - think I need to figure out the whole ModelState flow - if its coming out of there then there must be a step that loads stuff from ViewData etc
chrisb
Hey ... this is not even an answer ... how could you pick this up ??You can not set the selected value in Html extension method, you have to do it in the controller when building the ViewData
jalchr
+2  A: 

try setting the selected value in the controller action when creating the SelectList collection.

ViewData["AddressTypeId"] = new SelectList(CustomerService.AddressType_List(), "AddressTypeId", "Name", myItem.AddressTypeId);

IamNotaRobot
This solved the problem for me when trying to have a selected value for a dropdownlist's items. Thank you!
p.campbell
This also solved my problem.
Lalit
A: 

Ok I may be missing something from this thread however in C# the following works:

Html.DropDownList("ProfessionGuid", (SelectList)ViewData["Professions"])

Where 'ProfessionGuid' is the value to be selected in the list.

In VB.Net I believe it would be:

Html.DropDownList("ProfessionGuid", ViewData["Professions"] AS SelectList)
Aracnid
+12  A: 

Actually, you just have to pass in null for the Html.DropDownList().
I was having the same exact problem, and used the Reflector to look at the MVC Source Code.

In the System.Web.Mvc.Extensions.SelectExtensions class's SelectInternal() method, it checks whether the selectList parameter is null or not. If it is passed in as null, it looks up the SelectList properly.

Here is the "Code-behind".

ViewData["MyDropDown"] = new SelectList(selectListItems,
                             "Value",
                             "Text",
                             selectedValue.ToString()
                         );

Here is the HTML view code.

<%= Html.DropDownList("MyDropDown", null,
        "** Please Select **",
        new { @class = "my-select-css-class" }
    ) %>

Hope this helps,
Soe

Note: I'm using ASP.NET MVC 2.0 (Beta Version).

stun
Thanks ... that's the best solution for this problem with strongly typed views, I have ever seen ... It works with Model that has property name which matches the drop down name, and so it should ... thanks
jalchr
I agree. The "rename your field" mantra kills model binding to objects up front. This was the best solution for me as well.
claco
A: 

When you have problems with invalid or null ViewData, pay attention to your controller's action.

Suppose you have a ViewData called MyList for Html.DropDownlist called MyList.

If you call ModelState.AddModelError("MyList","Please select the profession") you'll replace your ViewData list content with the this warning text.

That's also why people around internet is having null problems with ViewData on DropDownList.

The bottom line is, pay attention to your IDs on error model, they must not interfere with your html controls.

Junior Mayhé
A: 

My concern with this is that you may only use the list for one field. I have Entities with multiple user fields, so I use the following.

< %= Html.DropDownList("fieldAAA", new SelectList( (IEnumerable) ViewData["Users"], "Value", "Text", fieldAAA))

%>