7

设置:

我已经使用 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 一起工作得很好)......而且我已经没有想法了。

4

1 回答 1

6

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

TL;博士; 问题是 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);
    }
    

    所以也许你无论如何都不想允许用户使用多种货币......

  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 只支持多选,所以它尝试处理defaultValueIEnumbrable

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

    在第二行有你的 ArgumentException 因为defaultValuesis null

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

于 2011-10-15T20:39:37.970 回答