【问题标题】:ListBox for ArgumentNullException Parameter name: sourceArgumentNullException 的 ListBox 参数名称:source
【发布时间】:2011-11-01 00:11:14
【问题描述】:

设置:

我已经使用 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,参数名称:源,但仅在编辑现有记录时。创建新记录,这工作正常。

问题:

发生了什么?!

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

模型不为空(就像我说的,它与 DropDownListFor 配合得很好)...而且我的想法已经用完了。

【问题讨论】:

  • 我注意到您没有检查 option == null 是否在 Value 行上。这只是一个疏忽吗?
  • 您得到的错误是 ViewBag.AllCurrencies 为空。我肯定会检查以确保它在您的操作方法中不为空。我知道你说它不是 null 但source 参数指的是Select 方法参数。
  • @BuildStarted:它不为空。如问题正文中所述,它适用于 DropDownListFor。相同的代码,相同的上下文。
  • @awrigley 你也可以发布你的模型的代码吗?您可以编辑问题并添加它。

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


【解决方案1】:

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

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

这是我的发现:

  1. ListBoxFor 方法将始终呈现具有multiple="multiple" 属性的select 元素。它被硬编码在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,因为它在调用 SelectInternal 时将 false 传递给 allowMultiple
    因为您的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 上进行多项选择,但您只会在模型中获得第一个选择。

【讨论】:

    猜你喜欢
    • 2018-09-29
    • 2019-11-26
    • 1970-01-01
    • 2015-07-25
    • 2014-10-29
    • 2015-07-17
    • 2014-02-18
    • 1970-01-01
    • 2021-10-09
    相关资源
    最近更新 更多