あなたはこれを絶対に行うことができますが、当初は問題に遭遇する傾向がありますので、完全な例を示します。
public class HomeController : Controller
{
public ActionResult Index()
{
// Assume this would really come from your database.
var employees = new List<EmployeeViewModel>()
{
new EmployeeViewModel { Id = 1, Name = "Employee 1" },
new EmployeeViewModel { Id = 2, Name = "Employee 2" },
new EmployeeViewModel { Id = 3, Name = "Employee 3" },
};
return View(employees);
}
[HttpPost]
public ActionResult Index(List<EmployeeViewModel> employees)
{
// Rest of action
}
}
人が最初にこの問題にアプローチの典型的な方法は、index.cshtml
で、次のような何かをすることです:
のは、
List<EmployeeViewModel>
を返す
Index
作用を有する
HomeController
を定義してみましょう、で開始する
@model List<EmployeeViewModel>
@using (Html.BeginForm())
{
foreach (var item in Model)
{
<div class="row">
@Html.EditorFor(x => item.Id)
</div>
<div class="row">
@Html.EditorFor(x => item.Name)
</div>
}
<input type="submit" />
}
一見、これはうまくいくように見えます。ただし、POSTアクションにブレークポイントを設定して[送信]ボタンをクリックすると、employees
はnull
になります。私はそこにいくつかの無関係な部分を取り除いてきた
<input name="item.Id" type="number" value="1" />
<input name="item.Name" type="text" value="Employee 1" />
<input name="item.Id" type="number" value="2" />
<input name="item.Name" type="text" value="Employee 2" />
<input name="item.Id" type="number" value="3" />
<input name="item.Name" type="text" value="Employee 3" />
が、name
属性は各従業員の同じ値を持っているかがわかりますforeach
ループは以下のようなHTMLを生成しているため、そのための理由があります。デフォルトのモデルバインダーがサーバー上のデータのリストを構築しようとすると、異なる従業員を区別することができなければならず、そうではないため、リストはnull
になります。
なぜ同じ値を生成していますか?それは、このためです:
@Html.EditorFor(x => item.Id)
@Html.EditorFor(x => item.Name)
情報が生成されたHTMLにそれを作るしないように私たちは、HtmlHelper
メソッド呼び出しにインデックス値を渡していません。私たちは今、各メソッド呼び出しでインデックスを供給していたよう
for (int i = 0; i < Model.Count; i++)
{
@Html.EditorFor(x => Model[i].Id)
@Html.EditorFor(x => Model[i].Name)
}
、生成されたHTMLは現在、各従業員のためのインデックスが含まれていない:私たちは、単に代わりfor
ループを利用することによってこの問題を解決することができ
<input name="[0].Id" type="number" value="1" />
<input name="[0].Name" type="text" value="Employee 1" />
<input name="[1].Id" type="number" value="2" />
<input name="[1].Name" type="text" value="Employee 2" />
<input name="[2].Id" type="number" value="3" />
<input name="[2].Name" type="text" value="Employee 3" />
デフォルトのモデルバインダーではId
とName
をそれぞれEmployeeViewModel
に関連付けて、サーバー上で型を正しく構築できます。
この時点で問題は解決されますが、避けることができる場合はfor
ループを使用することは推奨されません。これによりエディタテンプレートが表示されます。エディタテンプレートはHtmlHelper
のメソッドで、指定されたタイプのカスタムテンプレート(ビュー)をレンダリングできます。そこで、上記の例のコードを使用してそれを行う方法の例を示します。で開始する
、次の手順を実行する必要があります:
- (
EditorTemplates
名前はMVCで特別な意味を持っているので、それはそれを正しくスペルすることが重要です)あなたの~/Views/Home/
フォルダ内EditorTemplates
フォルダを作成します。 。
- このフォルダ内に
EmployeeViewModel.cshtml
ビューを作成します(ここでも重要なのは、カスタムテンプレートを作成するタイプの名前と一致する必要があります)。 、今
をEmployeeViewModel.cshtml
を開き、その中Index.cs
から、あなたのレンダリングコードを置く:あなたはそれをやった後は
、それは次のようになります
@model EmployeeViewModel
<div class="row">
@Html.EditorFor(x => x.Id)
</div>
<div class="row">
@Html.EditorFor(x => x.Name)
</div>
最後にindex.cshtml
を開き、次のように変更します。
、およびHtml.DisplayFor
、彼らはコレクションのために呼び出されているときに認識できるほど賢く両方なので、この場合には(コレクションのタイプをレンダリングするカスタムテンプレートを探し、EditorFor
は、エディタのテンプレートを探しますEmployeeViewModel
)。
エディタテンプレートを用意したので、コレクション内の各アイテムに対してレンダリングするだけでなく、モデルバインダーに再構築に必要なすべての情報を与える、それぞれのアイテムの正しいインデックスも生成しますサーバー上のそのコレクション。
最終的には、モデルのバインディングが簡単になり、ビューのコードが簡単になるだけでなく、関連するタイプに基づいて分割されるため、ビューの操作が簡単になります。すべてを行う巨大な眺め。
私の例ではコレクションを直接使用しているので、実際に@Html.EditorFor(x => x)
を@Html.EditorForModel()
に置き換えることもできます。私は最初にそれをしませんでした。なぜなら、後者を使ってテンプレートを呼び出すという印象を与えたくないからです。
ああ!どうもありがとうございます!! –
@ HarporSydneyようこそ。 :) –