43 votes

La modification du ViewBag de MVC 3 dans une vue partielle ne persiste pas dans le _Layout.cshtml

J'utilise MVC 3 avec le moteur de vue Razor. Je veux définir certaines valeurs dans le ViewBag à l'intérieur d'une vue partielle et je veux récupérer ces valeurs dans mon _Layout.cshtml. Par exemple, lorsque vous configurez un projet ASP.NET MVC 3 par défaut, vous obtenez un fichier _Layout.cshtml dans le dossier "/Views/Shared". Dans ce _Layout.cshtml, le titre de la page est défini comme suit :

<title>@ViewBag.PageTitle</title>

Ensuite, dans la vue "/Views/Home/About.cshtml", le contenu du ViewBag est modifié :

@{
    ViewBag.Title = "About Us";
}

Cela fonctionne bien. Lorsque la vue "About" est rendue, le titre de la page est "About Us". Donc, maintenant je veux rendre une vue partielle à l'intérieur de ma vue About et je veux modifier le ViewBag.Title à l'intérieur de ma vue partielle. ("/Views/Shared/SomePartial.cshtml")

@Html.Partial("SomePartial")

Dans cette vue partielle, j'ai ce code :

@{
    ViewBag.Title = "About Us From The Partial View";
}

Lorsque je débogue ce code, je vois que le ViewBag.Title est défini sur "About Us", puis dans la vue partielle, il est réinitialisé sur "About Us From The Partial View", mais lorsque le code atteint le _Layout.cshtml, il revient à "About Us".

Cela signifie-t-il que si le contenu du ViewBag est modifié dans une vue partielle, ces changements n'apparaîtront pas dans la vue principale (About.cshtml) ou dans le _Layout.cshtml ?

Merci d'avance !

32voto

Tony Basallo Points 1260

Si vous passez le ViewBag dans le viewdatadictionary du partiel, puis que vous le retirez (et que vous effectuez un casting), vous pouvez faire ce que vous voulez et la référence est conservée. La partie cool est que, puisque c'est dynamique, vous pouvez même ajouter des propriétés et elles apparaîtront dans le Viewbag de la page parent.

Page :

//set the viewbag into the partial's view data
@{Html.RenderPartial("Elaborate", Model, new ViewDataDictionary { {"vb", ViewBag}});}

Partiel :

@{
   var vb = ((dynamic)ViewData["vb"]);
   vb.TheTitle = "New values";
 }

Page

@ViewBag.TheTitle = "New value"

12voto

Chris Points 733

J'ai également eu ce problème, et je n'ai pas trouvé de solution claire et évidente.

La solution que j'ai trouvée est d'implémenter une méthode d'extension Html qui renvoie une classe 'PageData' que vous définissez, contenant les données dont vous avez besoin :

    [ThreadStatic]
    private static ControllerBase pageDataController;
    [ThreadStatic]
    private static PageData pageData;

    public static PageData GetPageData(this HtmlHelper html) {
        ControllerBase controller = html.ViewContext.Controller;
        while (controller.ControllerContext.IsChildAction) {
            controller = controller.ControllerContext.ParentActionViewContext.Controller;
        }
        if (pageDataController == controller) {
            return pageData;
        } else {
            pageDataController = controller;
            pageData = new PageData();
            return pageData;
        }
    }

Elle trouve le contrôleur de premier niveau pour la requête en cours et renvoie le même objet PageData chaque fois que la méthode est appelée dans la même requête HTTP. Elle crée un nouvel objet PageData la première fois qu'elle est appelée dans une nouvelle requête HTTP.

8voto

SLaks Points 391154

La vue partielle a sa propre ViewBag .

Vous pouvez obtenir le ViewBag de la page à partir de ((WebViewPage) WebPageContext.Current.Page).ViewBag

7voto

marianotigre Points 27

Vous pouvez utiliser cette astuce dans votre vue partielle pour remplacer le titre dans votre _Layout.cshtml :

@{
    ViewBag.Title = "About Us From The Partial View";
}

......

<script type="text/javascript">
    document.title = "@ViewBag.Title";
</script>

4voto

Dax70 Points 603

Comme d'autres l'ont souligné Mise en page , Vues y Partiels obtenir leur propre ViewBag . Cependant, j'ai réussi à le faire fonctionner en procédant comme suit : Dans la vue ou le partiel.

@{ Html.ViewContext.ViewBag.Title = "Reusable Global Variable"; }

Ensuite, dans _Layout

@Html.ViewContext.ViewBag.Title

En utilisant explicitement l'option ViewContext les vues "réutilisent" le même ViewBag.

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