我使用ASP.NET MVC 3,刚跑进使用一个“疑难杂症” DropDownListFor
HTML辅助。
我这样做,在我的控制器:
ViewBag.ShippingTypes = this.SelectListDataRepository.GetShippingTypes();
而GetShippingTypes
方法:
public SelectList GetShippingTypes()
{
List<ShippingTypeDto> shippingTypes = this._orderService.GetShippingTypes();
return new SelectList(shippingTypes, "Id", "Name");
}
我把它的原因ViewBag
而不是在模型(我强类型为每个视图模型),是我有呈现使用EditorTemplate,这也需要访问ShippingTypes选择列表项的集合。
否则,我需要遍历整个集合,并分配一个ShippingTypes属性即可。
到现在为止还挺好。
在我看来,我这样做:
@Html.DropDownListFor(m => m.RequiredShippingTypeId, ViewBag.ShippingTypes as SelectList)
( RequiredShippingTypeId
是类型Int32
)
什么情况是,该值RequiredShippingTypeId
没有在下拉选择向下。
我碰到这个传来: http://web.archive.org/web/20090628135923/http://blog.benhartonline.com/post/2008/11/24/ASPNET-MVC-SelectList-selectedValue-Gotcha.aspx
他认为,MVC将查找从选定值ViewData
,当选择列表是从ViewData
。 我不知道这样的话了,因为博客帖子是旧的,他在谈论MVC 1个测试版。
解决该问题的解决方法是这样的:
@Html.DropDownListFor(m => m.RequiredShippingTypeId, new SelectList(ViewBag.ShippingTypes as IEnumerable<SelectListItem>, "Value", "Text", Model.RequiredShippingTypeId.ToString()))
我试着不去ToString
上RequiredShippingTypeId
底,这给了我同样的行为像以前一样:没有选择的项目。
我想这是一个数据类型的问题。 最终,HTML帮助是比较字符串(在选择列表) Int32
(从RequiredShippingTypeId
)。
但为什么它不把选择列表的在工作时ViewBag
:当将其添加到模型时,而这样做的视图中完美的作品-
@Html.DropDownListFor(m => m.Product.RequiredShippingTypeId, Model.ShippingTypes)
为什么这不工作的原因是因为的限制DropDownListFor
助手:它能够推断使用仅如果 lambda表达式是一个简单的属性访问表达式第一个参数传递lambda表达式选择的值。 例如,这不符合数组索引访问表达式这是因为编辑器模板的工作你的情况。
你基本上(不包括编辑模板):
@Html.DropDownListFor(
m => m.ShippingTypes[i].RequiredShippingTypeId,
ViewBag.ShippingTypes as IEnumerable<SelectListItem>
)
以下是不支持: m => m.ShippingTypes[i].RequiredShippingTypeId
。 它仅适用于简单的属性访问表达式,但不与索引集合访问。
你已经找到了解决方法是解决这一问题,通过建立明确时,通过选择价值的正确方法SelectList
。
这可能是愚蠢的,但它添加到您的视图做任何一个变量?
var shippingTypes = ViewBag.ShippingTypes;
@Html.DropDownListFor(m => m.Product.RequiredShippingTypeId, shippingTypes)
你可以为复杂类型的每个下拉列表字段创建动态可视数据,而不是viewbag。 希望这会给你暗示该怎么做
@if (Model.Exchange != null) { for (int i = 0; i < Model.Exchange.Count; i++) { <tr> @Html.HiddenFor(model => model.Exchange[i].companyExchangeDtlsId) <td> @Html.DropDownListFor(model => model.Exchange[i].categoryDetailsId, ViewData["Exchange" + i] as SelectList, " Select category", new { @id = "ddlexchange", @class = "form-control custom-form-control required" }) @Html.ValidationMessageFor(model => model.Exchange[i].categoryDetailsId, "", new { @class = "text-danger" }) </td> <td> @Html.TextAreaFor(model => model.Exchange[i].Address, new { @class = "form-control custom-form-control", @style = "margin:5px;display:inline" }) @Html.ValidationMessageFor(model => model.Exchange[i].Address, "", new { @class = "text-danger" }) </td> </tr> } }
ViewModel CompanyDetail = companyDetailService.GetCompanyDetails(id); if (CompanyDetail.Exchange != null) for (int i = 0; i < CompanyDetail.Exchange.Count; i++) { ViewData["Exchange" + i]= new SelectList(companyDetailService.GetComapnyExchange(), "categoryDetailsId", "LOV", CompanyDetail.Exchange[i].categoryDetailsId); }
我只是通过这一限制击中,想出了一个简单的解决方法。 刚刚定义的在内部产生的扩展方法SelectList
与正确选择的项目。
public static class HtmlHelperExtensions
{
public static MvcHtmlString DropDownListForEx<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<SelectListItem> selectList,
object htmlAttributes = null)
{
var selectedValue = expression.Compile().Invoke(htmlHelper.ViewData.Model);
var selectListCopy = new SelectList(selectList.ToList(), nameof(SelectListItem.Value), nameof(SelectListItem.Text), selectedValue);
return htmlHelper.DropDownListFor(expression, selectListCopy, htmlAttributes);
}
}
最好的事情是,这个扩展可以使用的方式同原DropDownListFor
:
@for(var i = 0; i < Model.Items.Count(); i++)
{
@Html.DropDownListForEx(x => x.Items[i].CountryId, Model.AllCountries)
}
没有为@ html.DropdownList重载方法来处理这个问题。 还有就是要设置的HTML下拉列表中选择的值替代。
@Html.DropDownListFor(m => m.Section[b].State,
new SelectList(Model.StatesDropdown, "value", "text", Model.Section[b].State))
我能得到从模型中选择的值。
"value", "text", Model.Section[b].State
本节中的上述语法将所选属性从控制器加载的值