Generally, the Selected
property in SelectList
will be totally ignored by the HTML helpers unless there's no other option. If DropDownListFor
can find the value by other means, it will insist on using that value.
In this case, it will use the value of model.PersonType
(.ToString()
) - but that's not what you want, judging by the model.PersonType.ID
you pass to the SelectList
.
More info in the answer here.
Workaround
One easy workaround that should work would be to set:
ViewData["PersonType"] = model.PersonType.Id.
The helper looks in ModelState first if it exists - i.e. on POST. This should work already, since ModelState["PersonType"]
will be populated with the actual selected value that was posted.
After ModelState it will look in ViewData
- with ViewData["PersonType"]
first, and only then ViewData.Model.PersonType
. In other words, you can "override" the value on your model with a value set directly on ViewData
.
Better (IMO) solution
The more general, "better practice", way to solve it (which also avoids having a custom model binder in order to translate the POST'ed ID back to PersonType
) is to use a ViewModel instead of working with full models in your view:
- Have a
PersonTypeID
property - instead ofPersonType
. - Populate it with
PersonType.ID
- use this in your view
- VB.NET:
Html.DropDownListFor(Function(model) model.PersonTypeID)
, or - C#:
Html.DropDownListFor(model => model.PersonTypeID)
- VB.NET:
- When form is POST'ed, translate the ViewModel (including
PersonTypeID
=>PersonType
) back into the actual model in your POST Action.
This may seem like more work, but generally there tend to be many occasions in a project where you need more view-specific representations of your data to avoid too much inline Razor code - so translating from business objects to view models, while it may seem redundant and anti-DRY at times, tends to spare you of a lot of headaches.