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

Modifying MVC 3 ViewBag in a partial view does not persist to the _Layout.cshtml

我正在使用MVC 3和Razor View引擎。我想在一个局部视图内的视图包中设置一些值,并想在我的layout.cshtml中检索这些值。例如,当您设置默认的ASP.NET MVC 3项目时,会在"/views/shared"文件夹中得到一个u layout.cshtml文件。在该布局中,页面标题设置如下:

1
@ViewBag.PageTitle

然后在"/views/home/about.cshtml"视图中修改了视图包的内容:

1
2
3
@{
    ViewBag.Title ="About Us";
}

这个很好用。呈现"关于"视图时,页面标题为"关于我们"。所以,现在我想在我的"关于"视图中呈现一个局部视图,我想在局部视图中修改viewbag.title。("/views/shared/somepartial.cshtml")。

1
@Html.Partial("SomePartial")

在这个局部视图中,我有以下代码:

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

当我调试这个代码时,我看到viewbag.title被设置为"关于我们",然后在部分视图中,我看到它被重置为"关于部分视图中的我们",但是当代码到达Layout.cshtml时,它又回到"关于我们"。

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

事先谢谢!


如果将viewbag传递到分部的viewDataDictionary中,然后将其拉出(并强制转换),则可以执行所需的操作,并保留引用。最酷的部分是,由于它是动态的,您甚至可以添加属性,然后它们将显示在父页面的视图包中。

Page:

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

部分:

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

1
@ViewBag.TheTitle ="New value"


我也遇到了这个问题,找不到任何清晰而明显的解决方案。

我提出的解决方案是实现一个HTML扩展方法,该方法返回您定义的"pagedata"类,其中包含您需要的任何数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    [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;
        }
    }

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


您可以在部分视图中使用此技巧覆盖u layout.cshtml中的标题:

1
2
3
4
5
6
7
8
@{
    ViewBag.Title ="About Us From The Partial View";
}

......

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


局部视图有自己的ViewBag

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


正如其他人指出的布局,视图和局部视图都有自己的视图包。但是,我能够让它与以下内容一起工作:在视图中或部分视图中。

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

然后在布局中

@Html.ViewContext.ViewBag.Title

通过显式使用viewContext,视图"重用"同一个viewBag。


我尝试过以下方法,但效果很好:

在(父)视图中…

1
@Html.Partial("SomePartial", ViewData, null)

注:ViewData作为model参数传递,但必须为ViewData参数指定null才能使用正确的重载。你不能使用ViewBag,因为Html.Partial不喜欢动态。

然后,在局部视图中…

1
2
3
4
@model ViewDataDictionary
@{
    Model["Title"] ="About us from the partial view";
}

当然,如果你需要使用model的论证来建立一个真正的模型,你就必须更有创造性。


试用@slaks code

1
(((WebViewPage) WebPageContext.Current.Page).ViewBag).PropertyName

如果有人仍在寻找解决方案,您似乎可以使用tempdata:

1
TempData["x"] = x;

tempdata被持久化,直到它被读取,所以您可以在您的布局中读取它。你只需小心阅读所有内容,以便下一次请求时清除。


这就是页面数据的设计目的。将此弹出到您的视图中。

1
@Page.somePropertyName ="Whatever you want";

然后在布局视图中访问它。一定要先检查它是否不为空。

1
2
3
4
5
6
@{
    if(Page.somePropertyName != null)
    {
       //Do stuff
    }
}


我在使用MVC3时遇到了同样的问题,我发现

1
this.ViewBag.ViewBag.PropertyName

在自定义控件中工作。