この質問は、 Why is my DisplayFor not looping through my IEnumerable<DateTime>?のフォローアップです。
ささっとリフレッシュ。
いつ:
- モデルにはタイプのプロパティがあります
IEnumerable<T>
Html.EditorFor()
ラムダ式のみを受け入れるオーバーロードを使用して、このプロパティを渡しますT
Views/Shared/EditorTemplates の下にタイプのエディター テンプレートがあります。
次に、MVC エンジンは、列挙可能なシーケンス内の各項目のエディター テンプレートを自動的に呼び出し、結果のリストを生成します。
たとえば、Order
プロパティを持つモデル クラスがある場合Lines
:
public class Order
{
public IEnumerable<OrderLine> Lines { get; set; }
}
public class OrderLine
{
public string Prop1 { get; set; }
public int Prop2 { get; set; }
}
ビュー Views/Shared/EditorTemplates/OrderLine.cshtml があります。
@model TestEditorFor.Models.OrderLine
@Html.EditorFor(m => m.Prop1)
@Html.EditorFor(m => m.Prop2)
@Html.EditorFor(m => m.Lines)
次に、最上位ビューから呼び出すと、1 つだけでなく、各注文行のテキスト ボックスを含むページが表示されます。
ただし、リンクされた質問でわかるように、これは の特定のオーバーロードを使用する場合にのみ機能しますEditorFor
。テンプレート名を指定すると (クラスにちなんで名付けられていないテンプレートを使用するためにOrderLine
)、自動シーケンス処理は行われず、代わりに実行時エラーが発生します。
その時点で、カスタム テンプレートのモデルを として宣言しIEnumebrable<OrderLine>
、何らかの方法でそのアイテムを手動で繰り返し処理して、すべてを出力する必要があります。
@foreach (var line in Model.Lines) {
@Html.EditorFor(m => line)
}
そして、そこから問題が始まります。
この方法で生成された HTML コントロールは、すべて同じ ID と名前を持ちます。後でそれらを POST すると、モデル バインダーは の配列を作成できなくなりOrderLine
、コントローラーの HttpPost メソッドで取得するモデル オブジェクトは になりますnull
。
これは、ラムダ式を見ると理にかなっています。実際には、構築中のオブジェクトがモデル内の元の場所にリンクされているわけではありません。
アイテムを反復処理するさまざまな方法を試しましたが、テンプレートのモデルを次のように再宣言し、次のようIList<T>
に列挙することが唯一の方法のようfor
です。
@model IList<OrderLine>
@for (int i = 0; i < Model.Count(); i++)
{
@Html.EditorFor(m => m[i].Prop1)
@Html.EditorFor(m => m[i].Prop2)
}
次に、トップレベル ビューで:
@model TestEditorFor.Models.Order
@using (Html.BeginForm()) {
@Html.EditorFor(m => m.Lines, "CustomTemplateName")
}
これにより、送信時にモデル バインダーによって適切に認識される適切な名前の HTML コントロールが提供されます。
これは機能しますが、非常に間違っているように感じます。
EditorFor
エンジンがモデル バインダーに適した HTML を生成できるようにするすべての論理リンクを保持しながら、カスタム エディター テンプレートを で使用する正しい慣用的な方法は何ですか?