我使用MvcScaffolding搭建了一个控制器。
对于一个属性Model.IdCurrencyFrom,脚手架创建了一个Html.DropDownListFor:
@Html.DropDownListFor(model => model.IdCurrencyFrom,
((IEnumerable<FlatAdmin.Domain.Entities.Currency>)ViewBag.AllCurrencies).Select(option => new SelectListItem {
Text = (option == null ? "None" : option.CurrencyName),
Value = option.CurrencyId.ToString(),
Selected = (Model != null) && (option.CurrencyId == Model.IdCurrencyFrom)
}), "Choose...")
这种方法很好,包括新记录或编辑现有记录。
只有3种货币,AR $,US $和GB£。因此,我想要一个ListBox而不是下拉列表。
所以我把上面改为:
@Html.ListBoxFor(model => model.IdCurrencyFrom,
((IEnumerable<FlatAdmin.Domain.Entities.Currency>)ViewBag.AllCurrencies).Select(option => new SelectListItem {
Text = (option == null ? "None" : option.CurrencyName),
Value = option.CurrencyId.ToString(),
Selected = (Model != null) && (option.CurrencyId == Model.IdCurrencyFrom)
}))
我现在得到一个ArgumentNullException,参数名称:source,但仅在编辑现有记录时。创建新记录,这很好。
发生了什么事??
没有任何改变。切换回DropDownListFor,一切正常。切换到ListBox(而不是ListBoxFor),我收到错误。
该模型不为null(就像我说的,它适用于DropDownListFor)......而且我的想法已经用完了。
答案 0 :(得分:6)
我已经检查了HTML助手的来源,这是一个有趣的练习。
TL; DR;
问题是ListBoxFor用于多个选择,它需要一个可枚举的Model属性。您的模型属性(model.IdCurrencyFrom
)不是可枚举的,这就是您获得异常的原因。
以下是我的发现:
ListBoxFor方法将始终呈现具有select
属性的multiple="multiple"
元素。它在System.Web.Mvc.Html.SelectExtensions
private static MvcHtmlString ListBoxHelper(HtmlHelper htmlHelper, string name, IEnumerable<SelectListItem> selectList, IDictionary<string, object> htmlAttributes) {
return SelectInternal(htmlHelper, null /* optionLabel */, name, selectList, true /* allowMultiple */, htmlAttributes);
}
所以也许你不想让用户允许多种货币...
当此ListBoxHelper尝试从您的模型属性中获取默认值时,您的问题就开始了:
object defaultValue = (allowMultiple) ? htmlHelper.GetModelStateValue(fullName, typeof(string[])) : htmlHelper.GetModelStateValue(fullName, typeof(string));
适用于DropDownList,因为它在调用allowMultiple
时会将{false}传递给SelectInternal
由于您的ViewData.ModelState
为空(因为之前您的控制器中未发生任何验证),defaultValue
将为null
。然后使用您的模型的默认值初始化defaultValue
(我的情况model.IdCurrencyFrom
为int
),因此它将为0
。 :
if (!usedViewData) {
if (defaultValue == null) {
defaultValue = htmlHelper.ViewData.Eval(fullName);
}
}
我们接近异常:)因为我提到ListBoxFor只支持多项选择,所以它尝试将defaultValue
作为IEnumbrable
处理:
IEnumerable defaultValues = (allowMultiple) ? defaultValue as IEnumerable : new[] { defaultValue };
IEnumerable<string> values = from object value in defaultValues select Convert.ToString(value, CultureInfo.CurrentCulture);
在第二行有你的ArgumentException,因为defaultValues
是null
。
因为它希望defaultValue
可枚举,因为字符串是可枚举的。如果您将model.IdCurrencyFrom
的类型更改为string
,则可以使用。但是,当然您会在UI上进行多项选择,但您只能在模型中获得第一个选择。