web-dev-qa-db-ja.com

部分ビューに渡されるネストされた複雑なオブジェクトから値を取得する

メンバーの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属性を静的に設定できるので、より良い方法がない限り、私はビジネスに従事していると思いますか?

25
Blair Holmes

プレフィックスをパーシャルに渡すことができます

@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")
40
user3559349

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)

これが許容できる解決策ではない場合は、モデルバインダーのオーバーライドについて考える必要があるかもしれません。あなたはそれについて読むことができます ここ

2
Yogiraj

タグヘルパーを使用する場合、partialタグヘルパーはfor属性を受け入れます。

<partial name="MyPartialView" for="ComplexModel" />

一般的なfor属性ではなくmodel属性を使用すると、パーシャル内のすべてのフォームフィールドにComplexModel.接頭辞。

0
Todd

私は同じ状況に遭遇し、そのような有益な投稿の助けを借りて、部分ビューによって生成された入力要素に生成される接頭辞を持つように私の部分コードを変更しました

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メソッドを使用して、投稿されたフォームのモデルデータを更新しようとしました。

このアプローチに問題がないか、それとも少し多様化しているかをお知らせください。

0
Sachin Chauhan