ASP.NET MVCで深くネストされたビューモデルのフォームを作成する

ASP.NET MVCの深くネストされたビューモデルのフォームの作成に関するJimmy Bogardの別の興味深い投稿。 ASP.NET MVC 2を常に参照しているという事実にもかかわらず、この情報は3番目のバージョンにも関連しています。 無料翻訳のhabrakatオリジナル投稿の下。


ASP.NET MVC 2では、厳密に型指定されたビューでフォーム要素を作成するための多数の厳密に型指定されたヘルパーが導入されました。 これらの強く型付けされたヘルパーは、ラムダ式を使用して、要素の正しい名前と値を含む完全に完成した入力要素を作成します。

ラムダ式は非常に表現力豊かです。 編集用の非常に複雑なモデルを作成し、すべてをまとめるためにモデルをバインドすることができます。 複雑なビューモデルタイプの例:
public class ProductEditModel
{
public string Name { get ; set ; }
public PriceEditModel Price { get ; set ; }

public class PriceEditModel
{
public decimal Value { get ; set ; }
public string Currency { get ; set ; }
}
}

* This source code was highlighted with Source Code Highlighter .

彼のビューを作成するのは簡単です。
@using (Html.BeginForm()) {
< p >
@Html.LabelFor(m = > m.Name)
@Html.TextBoxFor(m = > m.Name)
</ p >
< p >
@Html.LabelFor(m = > m.Price.Currency)
@Html.TextBoxFor(m = > m.Price.Currency)
</ p >
< p >
@Html.LabelFor(m = > m.Price.Value)
@Html.TextBoxFor(m = > m.Price.Value)
</ p >
}

* This source code was highlighted with Source Code Highlighter .

モデルの最上位レベルから構築された式を使用して入力要素を作成する限り、正しいHMTLが取得されます。 ここでPriceEditModelを部分ビューにプルして、親ビューから分離するとします。 ビューでは、プロパティのレンダリングを部分ビューレンダリングに変更します。
@using (Html.BeginForm()) {
< p >
@Html.LabelFor(m = > m.Name)
@Html.TextBoxFor(m = > m.Name)
</ p >
@Html.Partial("_PriceEditModel", Model.Price);
}

* This source code was highlighted with Source Code Highlighter .

部分ビューは、PriceEditModelタイプに基づいていることを除いて、単なる切り取りビューコードです。
@model ProductEditModel.PriceEditModel

< p >
@Html.LabelFor(m = > m.Currency)
@Html.TextBoxFor(m = > m.Currency)
</ p >
< p >
@Html.LabelFor(m = > m.Value)
@Html.TextBoxFor(m = > m.Value)
</ p >

* This source code was highlighted with Source Code Highlighter .

ただし、結果のHTMLはモデルメンバーと正しく一致しなくなりました。 画面上ですべてが正常に並んでいるという事実にもかかわらず:


しかし、HTMLを調べるとすぐにエラーが表示されます。


「Price.Currency」のような名前に正しい親メンバーを持つメンバーの名前の代わりに、「Currency」のみが表示されます。 実際、POSTアクションに入ると、Priceメンバーはnullです。 モデルバインドで一致が見つかりませんでした:


正確に欲しいものではありません!

だから私たちのオプションは何ですか モデルバインディングが部分ビューのモデルで機能することを保証するために、部分ビューのこれらのモデルを親タイプにキャストできます。 つまり 「PriceEditModel」から「ProductEditModel」への部分ビューのモデルタイプを置き換えます。

非常に魅力的なオプションではありません!

より良いオプション-MVC 2のテンプレートヘルパーがあります。テンプレートヘルパーは、深くネストされたビューモデルの問題をエレガントに解決します。

テンプレートヘルパーを使用する


テンプレートベースのヘルパーは、HtmlHelperからHtml.EditorXyz()メソッドを使用するときに、特別なコンテキスト情報が親から子に渡されるという点で、部分ビューとは異なります。 ビューを再構築してテンプレートベースのヘルパーを使用するには、ビューモデルごとにエディターテンプレートを作成します。


これらのテンプレートは、特別なEditorTemplatesフォルダーに配置されることを除いて、Razorからの通常の部分ビューです。 ProductEditModelを使用した部分ビューの場合、ビューにあるすべてのものを単純に移動します。
@model ProductEditModel

< p >
@Html.LabelFor(m = > m.Name)
@Html.TextBoxFor(m = > m.Name)
</ p >
@Html.EditorFor(m = > m.Price)

* This source code was highlighted with Source Code Highlighter .

ただし、細かい点が1つあります。 Priceの部分ビューをレンダリングする代わりに、Priceメンバーのエディターをレンダリングしています。 PriceEditModelテンプレートは、変更なしで元の部分ビューにあったものです。
@model ProductEditModel.PriceEditModel

< p >
@Html.LabelFor(m = > m.Currency)
@Html.TextBoxFor(m = > m.Currency)
</ p >
< p >
@Html.LabelFor(m = > m.Value)
@Html.TextBoxFor(m = > m.Value)
</ p >

* This source code was highlighted with Source Code Highlighter .

現時点での違いは、テンプレートヘルパーは、親モデルが「価格」メンバーを使用して部分ビューを作成したことを知っていることです。 親ビューでは、編集はさらに簡単です:
@using (Html.BeginForm()) {
@Html.EditorForModel()
< input type ="submit" />
}

* This source code was highlighted with Source Code Highlighter .

EditorForModelメソッドを呼び出すときに、ASP.NET MVCはモデルタイプをチェックして、このモデルタイプのエディターテンプレートが存在することを確認します。 なぜなら モデルの個々のタイプごとにエディターテンプレートを作成します。これらのネストされたタイプが階層のどこにあるかは関係ありません。 ASP.NET MVCは親コンテキストを伝達するため、深くネストされたビューモデルにはそれに関する正しい情報が含まれます。

結果のHTMLを見て、すべてが正常であることを確認できます。


入力要素の名前には、有効な親プロパティ名が値として含まれるようになりました。 そして、POSTアクションのデバッグにより、モデルバインディングが正しく機能するようになりました。


ASP.NET MVC 2のテンプレートヘルパーを使用して、ビューにネストされたモデルを作成し、同時に部分ビューのすべての利点を取得できます。 唯一の注意点は、テンプレートヘルパーとHtml.EditorXyzメソッドを使用してビューを作成することです。 それ以外の場合、ビューへの影響は最小限になります。

文句を言うと、この方法はMVC 1.0では非常に面倒です。 MVCの古いバージョンに切り替えた後、大量のコードを投げました!

Source: https://habr.com/ru/post/J128026/


All Articles