2012-06-14 53 views
16

私はASP.NET MVC 3を使用していて、ちょうどDropDownListFor HTMLヘルパーを使用して「gotcha」を実行しました。ASP.NET MVC DropDownListForモデルから値を選択しない

私は私のコントローラでこれを実行します。

ViewBag.ShippingTypes = this.SelectListDataRepository.GetShippingTypes(); 

そしてGetShippingTypes方法:

public SelectList GetShippingTypes() 
{ 
    List<ShippingTypeDto> shippingTypes = this._orderService.GetShippingTypes(); 

    return new SelectList(shippingTypes, "Id", "Name"); 
} 

私はViewBagにしていないモデルでそれを置く理由(私は強く型付けされているモデルのために各ビュー)、私はEditorTemplateを使用してレンダリングするアイテムのコレクションを持っています。これはShippingTypesの選択リストにもアクセスする必要があります。

それ以外の場合は、コレクション全体をループして、ShippingTypesプロパティを割り当てる必要があります。

これまでのところとても良いです。私の見解では

、私はこれを行う:

@Html.DropDownListFor(m => m.RequiredShippingTypeId, ViewBag.ShippingTypes as SelectList) 

RequiredShippingTypeIdの値がドロップダウンで選択しないであること、である何が起こる

RequiredShippingTypeIdはタイプInt32です)。

私はこれに出くわした:http://web.archive.org/web/20090628135923/http://blog.benhartonline.com/post/2008/11/24/ASPNET-MVC-SelectList-selectedValue-Gotcha.aspx

彼は、選択リストがViewDataからあるときMVCは、ViewDataから選択した値をルックアップすることを示唆しています。ブログの投稿が古くて、MVC 1ベータについて話しているので、これはもうわかりません。

この問題を解決し、回避策はこれです:選択されていませんアイテム:

@Html.DropDownListFor(m => m.RequiredShippingTypeId, new SelectList(ViewBag.ShippingTypes as IEnumerable<SelectListItem>, "Value", "Text", Model.RequiredShippingTypeId.ToString())) 

は私が私の前と同じ動作を与える終わり、でRequiredShippingTypeIdToStringないようにしました。

私はこれがデータ型の問題だと思っています。最終的には、HTMLヘルパーは文字列(選択リスト内)をInt32RequiredShippingTypeId)と比較しています。

しかしViewBagでSelectListのを入れたときに、なぜそれが機能しない - モデルに追加し、ビュー内にこれをやったときに、それは完璧に動作したとき:

@Html.DropDownListFor(m => m.Product.RequiredShippingTypeId, Model.ShippingTypes) 
+0

ありがとう!それで、魔法は "単純な"ラムダ式でしか動作しないことが分かり、システムは警告を出さない。 –

答えて

30

これが動作しない理由は、理由DropDownListForヘルパーの制限がある:このラムダ式があるのみ場合、最初の引数として渡されたラムダ式を使用して、選択した値を推測することができます単純なプロパティアクセス式。たとえば、これはエディタテンプレートのためにあなたのケースである配列インデクサのアクセス式では機能しません。

あなたは基本的に(エディタテンプレートを除く)を持つ:

@Html.DropDownListFor(
    m => m.ShippingTypes[i].RequiredShippingTypeId, 
    ViewBag.ShippingTypes as IEnumerable<SelectListItem> 
) 

次がサポートされていません:m => m.ShippingTypes[i].RequiredShippingTypeId。単純なプロパティアクセス式でのみ動作しますが、インデックス付きのコレクションアクセスでは機能しません。

SelectListをビルドするときに選択した値を明示的に渡すことで、この問題を解決する正しい方法が見つかりました。

+0

くそー、私はそれを知らなかった。私はこれが事実であることを確認することができます。 '@Html.DropDownListFor(m => m.Product.RequiredShippingTypeId、ViewBag.ShippingTypes from SelectList)のドロップダウンのモデルではなく、' ViewBag'から 'ShippingTypes'を使用しようとしました。 ' - それは動作します。だから、私は醜い回避策に固執しなければならないと思う、私の意見に汚れたハックを残す代わりに、HTMLヘルパーを書くかもしれない。 – MartinHN

+0

@ダリン - これについてのドキュメントを教えてください。ありがとう。 – mokumaxCraig

+0

これは、他のオブジェクト/エイリアスを使用して値を取得している場合などにも当てはまります。 '@Html.DropDownListFor(m => myViewModel.RequiredShippingTypeID、...'。ありがとう! – xr280xr

0

これは愚かなことかもしれないが、あなたのビュー内の変数にそれを追加するのは何ですか?

var shippingTypes = ViewBag.ShippingTypes; 

@Html.DropDownListFor(m => m.Product.RequiredShippingTypeId, shippingTypes) 
+0

いいえ、これで問題は解決しません。 –

+0

私はそれを試したことはありませんが、@DarinDimitrovが正しいと確信しています。 – MartinHN

+0

kクールはちょうど私が可能な "クリーナー"の回避策としてそれを示唆したいと思った。 – Terry

0

これを処理するための@ html.DropdownListのオーバーロードされたメソッドがあります。 HTMLドロップダウンリストに選択した値を設定する方法もあります。

モデルから選択した値を取得できました。

"value", "text", Model.Section[b].Stateこのセクション上記の構文では、複合型のため、それぞれのDropDownListフィールドの代わりにviewbagのダイナミックのViewDataを作成することができるコントローラ

0

からロードされた値に選択した属性を追加します。これは与える 希望は、私はちょうどこの制限によりヒットし、簡単な回避策を考え出した

 @if (Model.Exchange != null) 
 
           { 
 
            for (int i = 0; i < Model.Exchange.Count; i++) 
 
            { 
 
             <tr> 
 
              @Html.HiddenFor(model => model.Exchange[i].companyExchangeDtlsId) 
 
              <td> 
 
                
 
               @Html.DropDownListFor(model => model.Exchange[i].categoryDetailsId, ViewData["Exchange" + i] as SelectList, " Select category", new { @id = "ddlexchange", @class = "form-control custom-form-control required" }) 
 
               @Html.ValidationMessageFor(model => model.Exchange[i].categoryDetailsId, "", new { @class = "text-danger" }) 
 
              </td> 
 
              <td> 
 
               @Html.TextAreaFor(model => model.Exchange[i].Address, new { @class = "form-control custom-form-control", @style = "margin:5px;display:inline" }) 
 
              
 
               @Html.ValidationMessageFor(model => model.Exchange[i].Address, "", new { @class = "text-danger" }) 
 
              </td> 
 
             </tr> 
 
            } 
 

 
           }

ViewModel CompanyDetail = companyDetailService.GetCompanyDetails(id); 
 
       if (CompanyDetail.Exchange != null) 
 
       for (int i = 0; i < CompanyDetail.Exchange.Count; i++) 
 
       { 
 
        ViewData["Exchange" + i]= new SelectList(companyDetailService.GetComapnyExchange(), "categoryDetailsId", "LOV", CompanyDetail.Exchange[i].categoryDetailsId); 
 
       }

0

ことを行う方法をヒント。適切に選択された項目で内部的にSelectListを生成する、ちょうど定義された拡張メソッド。

public static class HtmlHelperExtensions 
{ 
    public static MvcHtmlString DropDownListForEx<TModel, TProperty>(
     this HtmlHelper<TModel> htmlHelper, 
     Expression<Func<TModel, TProperty>> expression, 
     IEnumerable<SelectListItem> selectList, 
     object htmlAttributes = null) 
    { 
     var selectedValue = expression.Compile().Invoke(htmlHelper.ViewData.Model); 
     var selectListCopy = new SelectList(selectList.ToList(), nameof(SelectListItem.Value), nameof(SelectListItem.Text), selectedValue); 

     return htmlHelper.DropDownListFor(expression, selectListCopy, htmlAttributes); 
    } 
} 

最善のことは、この拡張機能は、元のDropDownListForと同じように使用することができることである。この問題を回避するための

@for(var i = 0; i < Model.Items.Count(); i++) 
{ 
    @Html.DropDownListForEx(x => x.Items[i].CountryId, Model.AllCountries) 
} 
関連する問題