I have the following line of code:
@Html.DropDownListFor(x => x.TimeOption, new SelectList(Model.TimeOptions, "Value", "Name", (int)Model.TimeOption))
The drop down is properly built, and Selected is indeed correct but MVC will not draw the drop down list with the correct item selected. The markup does not output a selected attribute on an option.
The output is rendered as:
<option value="0">Past Day</option>
<option value="1">Past Week</option>
<option value="2">Past Month</option>
<option value="3">Past Year</option>
<option value="4">Start of Time</option>
Yet if you look at the attached screenshot you can see it is correctly selected:
This affects only GET, not POST. Ideas?
This tends to stump people a lot - apparently the roadmap for MVC 5 includes more intuitive DropDownList helpers.
When you do:
@Html.DropDownListFor(x => x.TimeOption ...)
... the HTML helper will do everything in its power not to use the value you set to Selected = true
in your SelectList
. It will:
ModelState
- which it won't get on the GET requestViewData
- which it will get, because you have a TimeOption
property on your model.Only if both of those attempts fail, will it succumb, and use what you asked it to use.
So, in your case, it will use the current value of TimeOption
on your model as the selected value. Which should be fine, because that's what you asked for in your SelectList
anyway ((int)Model.TimeOption
), right?
Wrong. Because it will not cast your property (enum
?) to int
like you do. It will convert it to a string. For an enum
that yields the enumeration's name - e.g. PastMonth
. If TimeOption
is a custom class of yours, it will be the result of ToString()
.
Then, when it doesn't find that string as one of your <select>
values (because they're all integers), it decides not to make anything selected.
In short: SelectListItem.Selected
has no effect on the helper. If your helper call specifies a name (either literally or through a lambda expression), the helper will use anything in ModelState
or ViewData
with that name, and convert it to a string.
In most cases this happens with enumerations. The easiest way to get around it is to use the enumeration's name, rather than its int representation, as the value for the SelectListItem
.
You've already got a good explanation above as to why its not working, but just to add my 2p
Generally I prefer using an enumerable of SelectListItems as the source of dropdownitems, although either should work. It's just preferable doing it this way as there's no need to specified which item is selected - the MVC helper will infer it from the one who's Value matches the TimeOption.ToString() method.
ie
@Html.DropDownListFor(x => x.TimeOption, ((IEnumerable<TimeOption>)Model.TimeOptions).ToList().ConvertAll(y => new SelectListItem(){Text = y.Name, Value = y.Value.ToString()})
NB - I'm not sure what type Model.TimeOptions is here - if its not IEnumerable< TimeOption> then replace it. (if its already a list then .ToList() is not necessary)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With