メンバーの1つとして複雑なオブジェクトを持つViewModelがあります。複合オブジェクトには4つのプロパティ(すべて文字列)があります。再利用可能な部分ビューを作成して、複雑なオブジェクトを渡して、プロパティのhtmlヘルパーでhtmlを生成できるようにしています。それはすべてうまくいきます。ただし、フォームを送信すると、モデルバインダーは値をViewModelのメンバーにマッピングしていないため、サーバー側では何も返されません。ユーザーが複雑なオブジェクトのHTMLヘルパーに入力した値を読み取るにはどうすればよいですか。
ViewModel
public class MyViewModel
{
public string SomeProperty { get; set; }
public MyComplexModel ComplexModel { get; set; }
}
MyComplexModel
public class MyComplexModel
{
public int id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
....
}
コントローラ
public class MyController : Controller
{
public ActionResult Index()
{
MyViewModel model = new MyViewModel();
model.ComplexModel = new MyComplexModel();
model.ComplexModel.id = 15;
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// model here never has my nested model populated in the partial view
return View(model);
}
}
見る
@using(Html.BeginForm("Index", "MyController", FormMethod.Post))
{
....
@Html.Partial("MyPartialView", Model.ComplexModel)
}
パーシャルビュー
@model my.path.to.namespace.MyComplexModel
@Html.TextBoxFor(m => m.Name)
...
フォーム送信時にこのデータをバインドして、親モデルにWebフォームに部分ビューから入力されたデータが含まれるようにするにはどうすればよいですか?
ありがとう
編集:「ComplexModel」を付加する必要があることを理解しました。ネストされたオブジェクトにマップされるように、部分ビュー(テキストボックス)のすべてのコントロール名に追加しますが、ViewModelタイプを部分ビューに渡して、追加のレイヤーを取得することはできません。タイプ。 javascriptを使用してname属性を書き換えることもできましたが、それは私には過度にゲットーしているようです。他にどのようにこれを行うことができますか?
編集2:新しい{Name = "ComplexModel.Name"}を使用してname属性を静的に設定できるので、より良い方法がない限り、私はビジネスに従事していると思いますか?
プレフィックスをパーシャルに渡すことができます
@Html.Partial("MyPartialView", Model.ComplexModel,
new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "ComplexModel" }})
接頭辞を付加し、name
属性を制御するため、<input name="Name" ../>
となります <input name="ComplexModel.Name" ../>
およびポストバック時にtypeof MyViewModel
に正しくバインドします
編集
少し簡単にするために、これをhtmlヘルパーにカプセル化できます
public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, string partialViewName)
{
string name = ExpressionHelper.GetExpressionText(expression);
object model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model;
var viewData = new ViewDataDictionary(helper.ViewData)
{
TemplateInfo = new System.Web.Mvc.TemplateInfo
{
HtmlFieldPrefix = string.IsNullOrEmpty(helper.ViewData.TemplateInfo.HtmlFieldPrefix) ?
name : $"{helper.ViewData.TemplateInfo.HtmlFieldPrefix}.{name}"
}
};
return helper.Partial(partialViewName, model, viewData);
}
そしてそれを
@Html.PartialFor(m => m.ComplexModel, "MyPartialView")
ViewModelをパーシャルに渡してみることができます。
@model my.path.to.namespace.MyViewModel
@Html.TextBoxFor(m => m.ComplexModel.Name)
編集
ベースモデルを作成し、そこに複雑なモデルをプッシュして、ベースモデルをパーシャルに渡すことができます。
public class MyViewModel :BaseModel
{
public string SomeProperty { get; set; }
}
public class MyViewModel2 :BaseModel
{
public string SomeProperty2 { get; set; }
}
public class BaseModel
{
public MyComplexModel ComplexModel { get; set; }
}
public class MyComplexModel
{
public int id { get; set; }
public string Name { get; set; }
...
}
それからあなたの部分は以下のようになります:
@model my.path.to.namespace.BaseModel
@Html.TextBoxFor(m => m.ComplexModel.Name)
これが許容できる解決策ではない場合は、モデルバインダーのオーバーライドについて考える必要があるかもしれません。あなたはそれについて読むことができます ここ 。
タグヘルパーを使用する場合、partial
タグヘルパーはfor
属性を受け入れます。
<partial name="MyPartialView" for="ComplexModel" />
一般的なfor
属性ではなくmodel
属性を使用すると、パーシャル内のすべてのフォームフィールドにComplexModel.
接頭辞。
私は同じ状況に遭遇し、そのような有益な投稿の助けを借りて、部分ビューによって生成された入力要素に生成される接頭辞を持つように私の部分コードを変更しました
Html.partialのコンストラクターにHtml.partialヘルパーを使用して、Partialviewの名前とModelTypeのオブジェクト、およびHtml Field Prefixを持つViewDataDictionaryオブジェクトのインスタンスを指定しました。
これにより、「メインビュー」の「xyz url」のGETリクエストが生成され、その中に部分的なビューがレンダリングされます。以前のName = "Title"は、それぞれのHTML要素でName = "MySubType.Title"になり、残りのフォーム入力要素でも同じになります。
POSTリクエストが「xyz url」にリクエストされたときに問題が発生しました。入力されたフォームがデータベースに保存されることを期待しています。しかし、MVC ModelbinderはPOSTされたモデルデータを入力されたフォーム値とModelStateも失われ、viewdataのモデルもnullになりました。
最後に、モデルインスタンスと部分ビューに渡されたhtmlプレフィックスを取得するTryUppdateModelメソッドを使用して、投稿されたフォームのモデルデータを更新しようとしました。
このアプローチに問題がないか、それとも少し多様化しているかをお知らせください。