77 votes

Mises en page imbriquées de Razor avec sections en cascade

J'ai un site MVC3 utilisant Razor comme moteur de visualisation. Je veux que mon site soit skinnable. La plupart des habillages possibles sont suffisamment similaires pour pouvoir être dérivés d'une mise en page principale partagée.

Par conséquent, j'envisage cette conception :

Planned view diagram

Cependant, j'aimerais pouvoir appeler RenderSection dans la couche inférieure, _Common.cshtml et faire en sorte qu'il rende une section qui est définie dans la couche supérieure, Detail.cshtml . Cela ne fonctionne pas : RenderSection ne rend apparemment que les sections qui sont définies dans la couche supérieure suivante.

Bien sûr, je peux définir chaque section dans chaque peau. Par exemple, si _Common doit appeler RenderSection("hd") pour une section définie dans Detail je place simplement ceci dans chaque _Skin et ça marche :

@section hd {
    @RenderSection("hd")
}

Cela entraîne une certaine duplication du code (puisque chaque peau doit maintenant avoir cette même section) et est généralement désordonné. Je suis encore novice en matière de Razor et j'ai l'impression de passer à côté de quelque chose d'évident.

Lors du débogage, je peux voir la liste complète des sections définies dans WebViewPage.SectionWritersStack. Si je pouvais simplement dire à RenderSection de parcourir toute la liste avant d'abandonner, il trouverait la section dont j'ai besoin. Hélas, SectionWritersStack n'est pas public.

Sinon, si je pouvais accéder à la hiérarchie des pages de mise en page et tenter l'exécution de RenderSection dans chaque contexte différent, je pourrais localiser la section dont j'ai besoin. Je rate probablement quelque chose, mais je ne vois aucun moyen de faire cela.

Existe-t-il un moyen d'atteindre cet objectif, autre que la méthode que j'ai déjà exposée ?

35voto

marcind Points 38002

En fait, cela n'est pas possible aujourd'hui en utilisant l'API publique (sauf en utilisant l'approche de redéfinition de section). Vous pourriez avoir un peu de chance en utilisant la réflexion privée, mais il s'agit bien sûr d'une approche fragile. Nous chercherons à faciliter ce scénario dans la prochaine version de Razor.

En attendant, voici quelques articles de blog que j'ai rédigés sur le sujet :

17voto

Randy Points 141
@helper ForwardSection( string section )
{
   if (IsSectionDefined(section))
   {
       DefineSection(section, () => Write(RenderSection(section)));
   }
}

Cela ferait-il l'affaire ?

4voto

Alireza Noori Points 4428

Je ne sais pas si cela est possible dans MVC 3, mais dans MVC 5, j'ai réussi à le faire en utilisant l'astuce suivante :

Sur ~/Views/Shared/_Common.cshtml écrire votre code HTML commun comme :

<!DOCTYPE html>
<html lang="fa">
<head>
    <title>Skinnable - @ViewBag.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>

Sur ~/Views/_ViewStart.cshtml :

@{
    Layout = "~/Views/Shared/_Common.cshtml";
}

Maintenant, tout ce que vous avez à faire est d'utiliser la fonction _Common.cshtml comme le Layout pour toutes les peaux. Par exemple, dans ~/Views/Shared/Skin1.cshtml :

@{
    Layout = "~/Views/Shared/_Common.cshtml";
}

<p>Something specific to Skin1</p>

@RenderBody()

Vous pouvez maintenant définir le skin comme votre mise en page dans le contrôleur ou la vue en fonction de vos critères. Par exemple :

    public ActionResult Index()
    {
        //....
        if (user.SelectedSkin == Skins.Skin1)
            return View("ViewName", "Skin1", model);
    }

Si vous exécutez le code ci-dessus, vous devriez obtenir une page HTML contenant à la fois le contenu du fichier Skin1.cshtml y _Common.cshtml

En bref, vous allez définir la mise en page de la page de mise en page (de l'habillage).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X