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...")

これは、新しいレコードでも、既存のレコードの編集でも、正常に機能します。

問題:

通貨は、AR $、US $、GB£の3つだけです。したがって、ドロップダウンリストの代わりに、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に戻すと、すべて正常に機能します。(ListBoxForではなく)ListBoxに切り替えると、エラーが発生します。

モデルはnullではありません(私が言ったように、DropDownListForで正常に動作します)...そして私はアイデアを使い果たしました。

4

1 に答える 1

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

    とにかく、ユーザーに複数の通貨を許可したくないかもしれません...

  2. この ListBoxHelper がモデル プロパティからデフォルト値を取得しようとすると、問題が発生します。

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

    allowMultipleを呼び出すときにfalse を渡すため、DropDownList に対して機能し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); 
    

    そして2行目にはあなたのArgumentExceptionがありdefaultValuesますnull

  3. 列挙可能であることが期待defaultValueされ、文字列が列挙可能であるためです。のタイプをに変更するmodel.IdCurrencyFromと、機能しstringます。もちろん、UI では複数の選択が可能ですが、モデルでは最初の選択しか取得できません。

于 2011-10-15T20:39:37.970 に答える