ListBox for ArgumentNullException参数名称:source

时间:2011-08-22 09:31:10

标签: asp.net-mvc asp.net-mvc-3 asp.net-mvc-scaffolding html.listboxfor

设定:

我使用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)......而且我的想法已经用完了。

1 个答案:

答案 0 :(得分:6)

我已经检查了HTML助手的来源,这是一个有趣的练习。

TL; DR; 问题是ListBoxFor用于多个选择,它需要一个可枚举的Model属性。您的模型属性(model.IdCurrencyFrom)不是可枚举的,这就是您获得异常的原因。

以下是我的发现:

  1. 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);
    }
    

    所以也许你不想让用户允许多种货币...

  2. 当此ListBoxHelper尝试从您的模型属性中获取默认值时,您的问题就开始了:

    object defaultValue = (allowMultiple) ? htmlHelper.GetModelStateValue(fullName, typeof(string[])) : htmlHelper.GetModelStateValue(fullName, typeof(string)); 
    

    适用于DropDownList,因为它在调用allowMultiple时会将{false}传递给SelectInternal 由于您的ViewData.ModelState为空(因为之前您的控制器中未发生任何验证),defaultValue将为null。然后使用您的模型的默认值初始化defaultValue(我的情况model.IdCurrencyFromint),因此它将为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,因为defaultValuesnull

  3. 因为它希望defaultValue可枚举,因为字符串是可枚举的。如果您将model.IdCurrencyFrom的类型更改为string,则可以使用。但是,当然您会在UI上进行多项选择,但您只能在模型中获得第一个选择。