我正在使用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
的值未,会发生什么。
他建议当选择列表来自ViewData
时,MVC将从ViewData
中查找所选值。我不确定是不是这样了,因为博客文章已经过时了,他正在讨论MVC 1 beta。
解决此问题的解决方法是:
@Html.DropDownListFor(m => m.RequiredShippingTypeId, new SelectList(ViewBag.ShippingTypes as IEnumerable<SelectListItem>, "Value", "Text", Model.RequiredShippingTypeId.ToString()))
我最后在ToString
上尝试不RequiredShippingTypeId
,这给了我与以前相同的行为:没有选择任何项目。
我认为这是一个数据类型问题。最终,HTML帮助器将字符串(在选择列表中)与Int32
(来自RequiredShippingTypeId
)进行比较。
但是当将SelectList放在ViewBag
中时,为什么它在将它添加到模型时完美地工作,并在视图中执行此操作时不起作用:
@Html.DropDownListFor(m => m.Product.RequiredShippingTypeId, Model.ShippingTypes)
答案 0 :(得分:30)
这不起作用的原因是因为DropDownListFor
助手的限制:它能够使用作为第一个参数传递的lambda表达式来推断所选值这个lambda表达式是一个简单的属性访问表达式。例如,由于编辑器模板,这不适用于数组索引器访问表达式。
你基本上拥有(不包括编辑器模板):
@Html.DropDownListFor(
m => m.ShippingTypes[i].RequiredShippingTypeId,
ViewBag.ShippingTypes as IEnumerable<SelectListItem>
)
不支持以下内容:m => m.ShippingTypes[i].RequiredShippingTypeId
。它仅适用于简单的属性访问表达式,但不适用于索引集合访问。
通过在构建SelectList
时显式传递选定的值,您找到的解决方法是解决此问题的正确方法。
答案 1 :(得分:0)
这可能很愚蠢,但是在视图中将它添加到变量中会做什么吗?
var shippingTypes = ViewBag.ShippingTypes;
@Html.DropDownListFor(m => m.Product.RequiredShippingTypeId, shippingTypes)
答案 2 :(得分:0)
@ 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
此部分上面的语法将所选属性添加到从Controller
答案 3 :(得分:0)
您可以为复杂类型的每个下拉列表字段创建动态viewdata而不是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);
}
答案 4 :(得分:0)
我受到了这个限制,并想出了一个简单的解决方法。刚刚定义的扩展方法,内部生成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)
}