ListBox for ArgumentNullException参数名称:source

awr*_*ley 7 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...")
Run Code Online (Sandbox Code Playgroud)

无论是使用新记录还是编辑现有记录,这都可以正常工作.

问题:

只有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)
    }))
Run Code Online (Sandbox Code Playgroud)

我现在得到一个ArgumentNullException,参数名称:source,但仅在编辑现有记录时.创建新记录,这很好.

问题:

怎么了?!

什么也没有变.切换回DropDownListFor,一切正常.切换到ListBox(而不是ListBoxFor),我得到错误.

该模型不为null(就像我说的,它适用于DropDownListFor)...而且我的想法已经用完了.

nem*_*esv 6

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

TL; DR; 问题是ListBoxFor用于多个选择,它需要一个可枚举的Model属性.您的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);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    所以也许你不管怎样也不想允许用户使用多种货币......

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

    object defaultValue = (allowMultiple) ? htmlHelper.GetModelStateValue(fullName, typeof(string[])) : htmlHelper.GetModelStateValue(fullName, typeof(string)); 
    
    Run Code Online (Sandbox Code Playgroud)

    它适用于DropDownList,因为它allowMultiple在调用时传递false SelectInternal.
    因为你ViewData.ModelState是空的(因为你的控制器之前没有发生任何验证)defaultValue将是null.然后defaultValue使用您的模型的默认值进行初始化(我的情况model.IdCurrencyFrom就是int这样),所以它会是0.:

    if (!usedViewData) {
            if (defaultValue == null) {
                defaultValue = htmlHelper.ViewData.Eval(fullName);
            } 
     }
    
    Run Code Online (Sandbox Code Playgroud)

    我们接近异常:)因为我提到ListBoxFor只支持多个选择,所以它试图处理defaultValueIEnumbrable:

    IEnumerable defaultValues = (allowMultiple) ? defaultValue as IEnumerable : new[] { defaultValue };
    IEnumerable<string> values = from object value in defaultValues select Convert.ToString(value, CultureInfo.CurrentCulture); 
    
    Run Code Online (Sandbox Code Playgroud)

    在第二行有你的ArgumentException,因为defaultValuesnull.

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