在局部视图中修改MVC 3 ViewBag不会持久保存到_Layout.cshtml

Zor*_*ran 43 view partial razor viewbag asp.net-mvc-3

我正在使用带有Razor视图引擎的MVC 3.我想在部分视图中的ViewBag中设置一些值,并希望在_Layout.cshtml中检索这些值.例如,当您设置默认的ASP.NET MVC 3项目时,您将在"/ Views/Shared"文件夹中获得_Layout.cshtml文件.在_Layout.cshtml中,页面标题设置如下:

<title>@ViewBag.PageTitle</title>
Run Code Online (Sandbox Code Playgroud)

然后在"/Views/Home/About.cshtml"视图中修改ViewBag的内容:

@{
    ViewBag.Title = "About Us";
}
Run Code Online (Sandbox Code Playgroud)

这很好用.呈现"关于"视图时,页面标题为"关于我们".所以,现在我想在我的About视图中渲染一个Partial视图,我想修改我的Partial视图中的ViewBag.Title.( "/Views/Shared/SomePartial.cshtml")

@Html.Partial("SomePartial")
Run Code Online (Sandbox Code Playgroud)

在此部分视图中,我有以下代码:

@{
    ViewBag.Title = "About Us From The Partial View";
}
Run Code Online (Sandbox Code Playgroud)

当我调试这段代码时,我看到ViewBag.Title被设置为"关于我们",然后在Partial视图中我看到它被重置为"关于我们从部分视图",但是当代码命中_Layout.cshtml时它会去回到"关于我们".

这是否意味着如果在部分视图中修改了ViewBag的内容,那么这些更改将不会在主视图(About.cshtml)或_Layout.cshtml中显示(可访问)?

提前致谢!

Ton*_*llo 31

如果将ViewBag传递给partial的viewdatadictionary,然后将其拉出(并转换),您可以执行任何操作并保留引用.很酷的部分是,因为它是动态的,你甚至可以添加属性,然后它们将显示在父页面的Viewbag上.

页:

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

部分:

@{
   var vb = ((dynamic)ViewData["vb"]);
   vb.TheTitle = "New values";
 }
Run Code Online (Sandbox Code Playgroud)

@ViewBag.TheTitle = "New value"
Run Code Online (Sandbox Code Playgroud)

  • 或者,您可以直接将其添加到Page的视图包中.即在页面"ViewBag.PageBag = ViewBag;" 然后在部分"ViewBag.PageBag.Title ="新值"" (3认同)

Chr*_*ris 12

我也有这个问题,找不到任何简洁明了的解决方案.

我想出的解决方案是实现一个Html扩展方法,它返回一个你定义的'PageData'类,包含你需要的任何数据:

    [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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

它找到当前请求的顶级控制器,并在每次在同一HTTP请求中调用该方法时返回相同的PageData对象.它在第一次在新的HTTP请求中调用时创建一个新的PageData对象.

  • 我很惊讶ASP.NET MVC没有提供更好的方法来做到这一点.我能想到的是,我们要做的事情打破了MVC模式,但我们都知道在现实世界中会发生这种情况.我在当前项目中找到了解决此要求的方法,因此我没有机会尝试您的解决方案.但是谢谢你的意见.我会将其标记为已接受的答案,并希望它能帮助其他人.-谢谢 (2认同)

SLa*_*aks 8

部分视图有自己的特色ViewBag.

您可以从中获取页面的ViewBag ((WebViewPage) WebPageContext.Current.Page).ViewBag


小智 7

您可以在局部视图中执行此操作以覆盖_Layout.cshtml中的标题:

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

......

<script type="text/javascript">
    document.title = "@ViewBag.Title";
</script>
Run Code Online (Sandbox Code Playgroud)

  • 这不适用于SEO,因为它必须位于呈现的标记中 (3认同)