Razor:マスターページのマスターページにセクションを表示する

すべての良い一日。 最近、私はASP.NET MVC 3とRazorで「難しい」Webアプリケーションを積極的に開発しており、今日、経験豊富な開発者が既に調査および解決している問題に遭遇しましたが、初心者にとっては、以下の情報が役立つと思います便利です。



問題の説明



アプリケーションにView.cshtmlとViewWithSide.cshtmlのビューがいくつかあるとします。また、2つのマスターページがあります。Layout.cshtmlとLayoutWithSide.cshtmlです。1つ目は2つ目のマスターページです。 ファイル名から推測できるように、XxxWithSide.cshtmlはページにサイドバーを追加します。サイドバーの出力形式はマスターページで定義され、ビューの内部は定義されます。 メインレイアウトマスターページでは、メインレイアウトに加えて、「ナビゲーション」セクションの出力が定義され、ビューで設定されます。



そして今、「ナビゲーション」セクションがViewWithSideコードで定義されているが、LayoutWithSideでは定義されていない場合、このセクションは「次の」マスターページ(レイアウト)で処理される必要があるため、アプリケーションでViewWithSideを開こうとするとエラーが発行されます: 次のセクションが定義されましたレイアウトページ "〜/ Views / Shared / LayoutWithSide.cshtml": "navigation" ( " Navigation" セクションが定義されていますが、マスターページのどこにも表示 されていません)に対してレンダリングされて いません



この問題を解決するアイデアは非常に簡単です。このセクションの出力を「次の」マスターページに転送し、そこで理解してもらう必要があります。



いくつかのコード



Layout.cshtml

<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <div> @if (IsSectionDefined("navigation")) { <div class="navigation">@RenderSection("navigation")</div> } @RenderBody() </div> </body> </html>
      
      





LayoutWithSide.cshtml

 @{ Layout = "~/Views/Shared/Layout.cshtml"; } <div class="side">@RenderSection("side", required:false)</div> <div class="main">@RenderBody()</div>
      
      





View.cshtml

 @{ ViewBag.Title = "view"; Layout = "~/Views/Shared/Layout.cshtml"; } @section navigation { <a href="@Url.Action("Page1")">page1</a> | <a href="@Url.Action("Page2")">page2</a> } <h2>viewWithoutSide</h2> <div>Main content</div>
      
      





ViewWithSide.cshtml

 @{ ViewBag.Title = "viewWithSide"; Layout = "~/Views/Shared/LayoutWithSide.cshtml"; } @section navigation { <a href="@Url.Action("Page1")">page1</a> | <a href="@Url.Action("Page2")">page2</a> } @section side { <strong>side content</strong> } <h2>viewWithSide</h2> <div>Main content</div>
      
      





当然、RazorとASP.NET MVCがそれを把握し、必要なマスターページのセクションを表示することを期待していました。 しかし、悲しいかな...しかし、問題があり、解決する方法のアイデアがあります-解決する必要があります。



ソリューションを検索する



私の場合、「ナビゲーション」セクションは単なるオプションではありませんが、定義されていない場合は、マークアップの一部が表示されません。 このため、LayoutWithSideに同じ名前のセクションを入力し、ビューから転送されたコンテンツを表示するだけでは機能しません。



私はif (IsSectionDefined("navigation"))



でセクション宣言をラップしようとしましたが、多分...このメソッドに特に希望はありませんでした-うまくいきませんでした(アナライザーはそのようなデザインを期待せず、「パーサーエラー」を宣誓します)。



MSDNおよびインターネットでの迅速で表面的な検索では、有用なものは何も得られませんでした。 しかし、ビュー内で使用可能なメソッドでは、 DefineSectionメソッド(文字列名、SectionWriterアクション)がすぐに気付きました



if宣言でRazorスタイルのセクション宣言をラップすることはできなかったため、C#コードからセクション作成をラップすることができます。 次のようになりました。

 if (IsSectionDefined("navigation")) { DefineSection("navigation", delegate() { Write(RenderSection("navigation")); }); }
      
      





そして、このコードは正常に機能し、タスクを完了しました。



解決策



もちろん、マスターページに転送する必要のある各セクションこのようなコードをあまり多く書かないように、そこで止まりませんでした。

ファッショナブルで便利な拡張メソッドC#を自由に使用できます。 その結果、次のクラスを作成しました。

 public static class WebPageHelpers { public static void PropagateSection(this WebPageBase page, string sectionName) { if (page.IsSectionDefined(sectionName)) { page.DefineSection(sectionName, delegate() { page.Write(page.RenderSection(sectionName)); }); } } public static void PropagateSections(this WebPageBase page, params string[] sections) { foreach (var s in sections) PropagateSection(page, s); } }
      
      





そして、プロジェクトに接続したら、メソッドを呼び出して、必要なセクションの名前を渡します。 この場合、LayoutWithSide.cshtmlは次のようになります。

 @{ Layout = "~/Views/Shared/Layout.cshtml"; this.PropagateSection("navigation"); } <div class="side">@RenderSection("side", required:false)</div> <div class="main">@RenderBody()</div>
      
      





複数のセクションをマスターページに転送する必要がある場合は、 this.PropagateSections("section1", "section2", "section3")



呼び出すことができます。



All Articles