Razorをビューエンジンとして使用するMVC3サイトがあります。自分のサイトをスキン可能にしたい。可能なスキンのほとんどは、共有マスターレイアウトから派生できるほど十分に類似しています。
したがって、私はこの設計を検討しています:
ただし、一番下のレイヤー__Common.cshtml
_でRenderSection
を呼び出し、一番上のレイヤー_Detail.cshtml
_で定義されているセクションをレンダリングできるようにしたいと思います。これは機能しません:RenderSection
は明らかに、次のレイヤーで定義されたセクションのみをレンダリングします。
もちろん、各スキンの各セクションを定義できます。たとえば、Detail
で定義されたセクションに対して__Common
_がRenderSection("hd")
を呼び出す必要がある場合、これを各__Skin
_に配置するだけで機能します。
_@section hd {
@RenderSection("hd")
}
_
これにより、コードの重複が発生し(各スキンには同じセクションが必要になるため)、通常は煩雑に感じます。私はまだRazorに慣れていないので、明らかな何かを見逃しているようです。
デバッグ時には、WebViewPage.SectionWritersStackで定義済みセクションの完全なリストを見ることができます。あきらめる前にリスト全体を調べるようにRenderSectionに指示できれば、必要なセクションが見つかります。残念ながら、SectionWritersStackは非公開です。
あるいは、レイアウトページの階層にアクセスして、それぞれ異なるコンテキストでRenderSectionの実行を試みることができれば、必要なセクションを見つけることができます。私はおそらく何かを見逃していますが、これを行う方法がわかりません。
既に説明した方法以外に、この目標を達成する方法はありますか?
これは、実際には、パブリックAPIを使用して(セクションの再定義アプローチを使用する以外は)実際には不可能です。プライベートリフレクションを使用すると多少の幸運があるかもしれませんが、それはもちろん脆弱なアプローチです。 Razorの次のバージョンでは、このシナリオを簡単にすることを検討します。
それまでの間、このテーマについて私が書いたいくつかのブログ投稿があります。
@helper ForwardSection( string section )
{
if (IsSectionDefined(section))
{
DefineSection(section, () => Write(RenderSection(section)));
}
}
これは仕事をしますか?
MVC 3でこれが可能かどうかはわかりませんが、MVC 5では次のトリックを使用してこれを正常に行うことができます:
~/Views/Shared/_Common.cshtml
に、次のような一般的なHTMLコードを記述します。
<!DOCTYPE html>
<html lang="fa">
<head>
<title>Skinnable - @ViewBag.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>
~/Views/_ViewStart.cshtml
::
@{
Layout = "~/Views/Shared/_Common.cshtml";
}
あとは、すべてのスキンのLayout
として_Common.cshtml
を使用するだけです。たとえば、~/Views/Shared/Skin1.cshtml
:
@{
Layout = "~/Views/Shared/_Common.cshtml";
}
<p>Something specific to Skin1</p>
@RenderBody()
これで、基準に基づいてスキンをコントローラーまたはビューのレイアウトとして設定できます。例えば:
public ActionResult Index()
{
//....
if (user.SelectedSkin == Skins.Skin1)
return View("ViewName", "Skin1", model);
}
上記のコードを実行する場合、Skin1.cshtml
と_Common.cshtml
の両方のコンテンツを含むHTMLページを取得する必要があります
つまり、(スキン)レイアウトページのレイアウトを設定します。
これが役立つかどうかはわかりませんが、パーシャル内からセクションを「バブルアップ」するのに役立つ拡張メソッドをいくつか作成しました。これはネストされたレイアウトでも機能するはずです。
Razor View Engineを使用した部分ビューASP.NET MVC 3から特定のセクションにコンテンツを挿入
子レイアウト/ビュー/部分で宣言
@using (Html.Delayed()) {
<b>show me multiple times, @Model.Whatever</b>
}
任意の親でレンダリング
@Html.RenderDelayed();
繰り返しビューで宣言されていても1つの遅延ブロックのみをレンダリングする、特定の遅延ブロックをレンダリングするなど、その他のユースケースについては、回答リンクを参照してください。