0

カスタム モデルのコレクションにビューをバインドしたいと考えています。一般的な方法でこれを行い、ビューからモデル項目をループし、モデルを記述するときにブラケット構文を使用する場合、これは問題になりません。

すなわち:

@Html.HiddenFor(m => Model[i].Id)

私の問題は、モデル アイテムをグループ化する必要があるため、アイテムのサブセレクションを作成したことです。

@foreach(var itemType in Model.GroupBy(item => item.Type).Select(grp => grp.First()))
{
    <p>@itemType:</p>

    var selection = Model
        .Where(p => p.Type == itemType)
        .OrderBy(p => p.CreationDate);

    for (int i = 0; i < selection.Count(); i++) {
       @Html.HiddenFor(m => selection[i].Id)
       @* all my other element bindings here... *@
       ...
    }

さて、問題は、送信されたフォームを受け取るコントローラー メソッドが空のモデルを取得することです。そのため、モデルのシリアル化はある時点で壊れています。多分MVCは私の「選択」変数名が気に入らないのでしょうか?..または、私の問題は何でしょうか?どうすれば解決できますか?

4

1 に答える 1

1

問題は、ビューが生成されるときに各項目に対して生成される名前にあります。モデル バインダーは、名前と値のペアを使用して、コントローラーで予期されるビュー モデルにフォームの値をマップする方法を見つけます。

を使用していた場合@Html.HiddenFor(m=>m[i].Id)は問題なく、HTML に次の name 属性が生成されます。

name="[0].ModelId"

後のものは

name="[5].ModelId"

など。

ビューで生成される HTML は次のとおりです。

ビューの HTML ソース

ここには 2 つの問題があります。

  1. 名前の先頭に値「selection」が表示されます
  2. 配列インデックスとしてゼロを2回使用しています

これは、末尾に for を持つすべての HTML タグ (HiddenFor、TextboxFor など) が機能するために発生します。ラムダ式に基づいて名前属性を決定します-m => m[0].ModelId最初のもので使用[0].ModelIdしていたため、名前として使用されました。2番目では、を使用するm=> selection[0].ModelIdため、使用selection[i].ModelIdされます(ラムダの一部として使用した変数はすべて削除されます.

それで、これをどのように修正しますか?

現在のセットアップでは、2 つの方法のいずれかでこれにアプローチできます。ループの外側でカウンターを使用してそれを配列インデックスとして使用するか、追加の非表示フィールドをインデックス フィールドとして使用することができます。どちらのアプローチでも、生成される HTML 要素の名前を手動で設定できるように、厳密に型指定された HiddenFor/TextBoxFor を削除し、代わりに Hidden/TextBox を使用する必要があります。

インデックス フィールドで何が起こるかは、次のようなアイテム名を持っていることです。

<input type="hidden" name="Index" value="Model1"/>
<input type="hidden" name="[Model1].ModelId" value="1"/>
<input type="hidden" name="[Model1].ModelValue" value="Some value"/>

最初の入力タグでは、これを index と呼び、この関連する一連の値のインデックスとして機能する値を設定しました。残りのものでは、最初の値として設定された値を配列インデックスとして使用し、次にプロパティの名前のみを使用しました。このアプローチは、リストにアイテムを追加/削除している状況にあり、ポストバックするときにすべての番号が順番にあることを保証できない場合に特に役立ちます.

Razor コードは次のようになります。

for (int i = 0; i < selection.Count(); i++) {
    @Html.Hidden("Index", "Model"+selection[i].ModelId)
    @Html.Hidden("[Model"+selection[i].ModelId + "].ModelId", selection[i].ModelId)
    @Html.Hidden("[Model"+selection[i].ModelId + "].CreateDate", selection[i].CreateDate)
    @Html.Hidden("[Model"+selection[i].ModelId + "].ModelValue", selection[i].ModelValue)

補足として、インデックスの一部として「モデル」という単語を含めることを選択したので、配列内の番号の場所ではなく、辞書のようなエントリとして参照していることを確実に認識できます。絶対にそのようにする必要があるかどうかはわかりません。実際に他の方法を試したことはありません。ModelId をインデックス値として使用しました。これは、一意の値であることが望ましいためです。

最終結果は、次のような HTML を生成する必要があります (name 属性に関して):

ここに画像の説明を入力

うまくいけば、それは役に立ちます!

于 2013-05-26T20:38:28.513 に答える