モデルのサブコレクションを編集するのに長い間立ち往生していて、モデルのコレクションがnullになりました。
私はついに解決策を見つけましたが、少し汚れています:
最初に私のテストデータ:
モデルオブジェクト:
public class ContainerObject
{
public String Title { get; set; }
public List<ContainedObject> ObjectList { get; set; }
}
サブコレクションオブジェクト:
public class ContainedObject
{
public int Id { get; set; }
public String Text { get; set; }
public Boolean IsSelected { get; set; }
}
オブジェクトを生成するコントローラーメソッド
public ActionResult TestForm()
{
return View(new ContainerObject()
{
Title = "This is a sample title",
ObjectList = new List<ContainedObject>()
{
new ContainedObject(){Id=1, IsSelected = true, Text="ObjectOne"},
new ContainedObject(){Id=2, IsSelected = false, Text="ObjectTwo"},
new ContainedObject(){Id=3, IsSelected = true, Text="ObjectThree"},
new ContainedObject(){Id=4, IsSelected = false, Text="ObjectFour"},
}
});
}
編集されたオブジェクトを受け取るコントローラー
[HttpPost]
public ActionResult TestFormResult(ContainerObject filledObject)
{
return View();
}
ビュー
@model WebTestApplication.Models.ContainerObject
@{
ViewBag.Title = "TestForm";
}
@using (Html.BeginForm("TestFormResult","Home", FormMethod.Post)){
@Html.EditorFor(x => x.Title)
Html.RenderPartial("ContainedObject", Model.ObjectList);
<input type="submit" value="Submit"/>
}
部分ビュー(ContainedObject.cshtml)
@model IEnumerable<WebTestApplication.Models.ContainedObject>
@{
ViewBag.Title = "ContainedObject";
int i = 0;
}
@foreach (WebTestApplication.Models.ContainedObject currentObject in Model)
{
<br />
@Html.Label(currentObject.Text);
@Html.CheckBox("ObjectList[" + i + "].IsSelected", currentObject.IsSelected);
@Html.Hidden("ObjectList[" + i + "].Id", currentObject.Id);
@Html.Hidden("ObjectList[" + i + "].Text", currentObject.Text);
i++;
}
これは実際には機能していますが、問題が1つあります。
ビューでHtml.EditorFor
の代わりにHtml.RenderPartial
を使用しようとしましたが、問題は、「ObjectList。[0] .Id」という名前が生成されることです(プロパティ名とアクセサーの間に。が追加されています)。 )。
また、部分ビューで@ Html.EditorForのみを使用しようとしましたが、オブジェクトの名前で変数が作成されます。
テンプレートを使用しない場合は、次のように機能します。
@model WebTestApplication.Models.ContainerObject
@{
ViewBag.Title = "TestForm";
}
@using (Html.BeginForm("TestFormResult", "Home", FormMethod.Post))
{
@Html.EditorFor(x => x.Title)
for (int i = 0; i < Model.ObjectList.Count; i++)
{
<br />
@Html.Label(Model.ObjectList[i].Text);
@Html.CheckBoxFor(m => Model.ObjectList[i].IsSelected);
@Html.HiddenFor(m => Model.ObjectList[i].Id);
@Html.HiddenFor(m => Model.ObjectList[i].Text);
}
<br /><input type="submit" value="Submit"/>
}
これは単純なテンプレートですが、実際の場合、はるかに多くのデータがあり、これは何度も再利用されます。それで、私の最良の選択肢は何ですか?
EditorTemplateを導入することで、コードを簡略化できます。方法は次のとおりです。
TestForm.cshtml
@model WebTestApplication.Models.ContainerObject
@{
ViewBag.Title = "TestForm";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm("TestFormResult", "Home", FormMethod.Post)) {
@Html.EditorFor(m => m.Title)
@Html.EditorFor(m => m.ObjectList);
<input type="submit" value="Submit" />
}
ContainedObject.cshtml
@model WebTestApplication.Models.ContainedObject
<p>
@Html.DisplayFor(m => m.Text)
@Html.CheckBoxFor(m => m.IsSelected)
@Html.HiddenFor(m => m.Id)
@Html.HiddenFor(m => m.Text)
</p>
エディターは、各オブジェクトのビューをレンダリングするオブジェクトのリストを自動的に繰り返します。それが役に立てば幸い。
他に関連するものを探しているときにこのスレッドを見つけました。デニスは正解ですが、他の誰かがこれに遭遇した場合に備えて、構文を追加すると思いました。
「SomeTemplate.cshtml」という名前のエディターテンプレートがある場合は、ビューで次のようにアイテムのリストに使用できます。
@for (var i = 0; i < Model.ObjectList.Count(); i++)
{
@Html.EditorFor(m => m.ObjectList[i], "SomeTemplate")
}
次に、エディターテンプレートで:
@model WebTestApplication.Models.ContainedObject
<br />
@Html.Label(Model.Text);
@Html.CheckBoxFor(m => m.IsSelected);
@Html.HiddenFor(m => m.Id);
@Html.HiddenFor(m => m.Text);