问题
I have this to populate a drop down list in an ASP.NET MVC view.
<%= Html.DropDownListFor(model => model.Bikes,
Model.Bikes.Select(
x => new SelectListItem {
Text = x.Name,
Value = Url.Action("Details", "Bike", new { bikeId = x.ID }),
Selected = x.ID == Model.ID,
})) %>
Debugging this I can see that the Selected
property is set to true
when it should be. But when the view is rendered, none of the options in the list is selected. I realize that this could be done with another overload of DropDownListFor
but I really want to get this version working.
Any ideas?
回答1:
The reason your selected value doesn't work is because you are using Urls as option values but specifying Model.ID
in the Selected
clause.
Try like this:
<%= Html.DropDownListFor(
model => model.Bikes,
new SelectList(Model.Bikes, "Id", "Name", Model.ID)
)%>
"Id"
indicates the property that will be used as option value while "Name"
indicates the property that will be used as option label.
If you want to preserve the Url.Action
you could try:
<%= Html.DropDownListFor(
model => model.Bikes,
new SelectList(Model.Bikes.Select(x => new {
Id = x.Id,
Name = Url.Action("Details", "Bike", new { bikeId = x.ID })
}), "Id", "Name", Model.ID)
)%>
You will notice that I've inverted the Name and Id as it seemed more logical to use the model Id as option value.
UPDATE:
The reason this doesn't work is because you are binding to an IEnumerable
(the first argument of the DropDownListFor
helper). It should be a scalar property while you are using the same model.Bikes
collection:
<%= Html.DropDownListFor(
model => model.SelectedBikeValue,
Model.Bikes.Select(
x => new SelectListItem {
Text = x.Name,
Value = Url.Action("Details", "Bike", new { bikeId = x.ID }),
Selected = x.ID == Model.ID,
}
)) %>
My remark about not using Urls as option values stands true.
回答2:
I've had so many troubles with this concept. It especially manifests itself when you cannot pass it "name" property from the model that contains that property in an object, because such object name is automatically prepended to the name. This is crazy. After wasting many hours trying to figure this one out I just gave up and wrote my own Drop-Down extension which I publish here. It is very simple and it works just fine.
public static MvcHtmlString SimpleDropDown(this HtmlHelper helper, object attributes, IEnumerable<SelectListItem> items, bool disabled = false)
{
XElement e = new XElement("select",
items.Select(a => {
XElement option = new XElement("option", a.Text);
option.SetAttributeValue("value", a.Value);
if (a.Selected)
option.SetAttributeValue("selected", "selected");
return option;
})
);
if (attributes != null)
{
Dictionary<string, string> values = (from x in attributes.GetType().GetProperties() select x).ToDictionary(x => x.Name, x => (x.GetGetMethod().Invoke(attributes, null) == null ? "" : x.GetGetMethod().Invoke(attributes, null).ToString()));
foreach(var v in values)
e.SetAttributeValue(v.Key, v.Value);
}
if (disabled)
e.SetAttributeValue("disabled", "");
return new MvcHtmlString(e.ToString());
}
Also, I put flag disabled as an extra parameter, because if you want to bind to it via the standard anonymous list of attributes, it can be quite a hassle.
Below is an example of how I use it at the moment. I translate a dictionary into a list of SelectListItem, but it can be just a simple list.
@Html.SimpleDropDown(new { id="EOM", name = "EOM", @class = "topBox" }, Model.EOM.Select(x => new SelectListItem { Text = x.Value, Value = x.Key.ToString(), Selected = Model.EOM.Selected == x.Key }), !Model.EOM.Available)
来源:https://stackoverflow.com/questions/3352373/asp-net-mvc-dropdownlistfor-doesnt-select-any-option