在ASP.NET MVC中通过子操作设置页面标题

时间:2013-10-04 23:21:35

标签: c# asp.net asp.net-mvc-4

在我的ASP.NET MVC4中,我允许控制器通过设置ViewBag.PageTitle来设置当前页面标题。 但

第1部分。当在ChildAction中设置ViewBag.PageTitle时,它不起作用(_Layout.cshtml看不到它);如何从ChildAction设置页面标题?

第2部分。如何在缓存的ChildAction中设置页面标题,因为缓存时不再调用该操作?

谢谢!

public ActionResult Product(long productId)
{
    ViewBag.PageTitle="test";   //Works
    return View(productId);
}

[OutputCache(Duration=300)]
[ChildActionOnly]
public ActionResult ProductPartial(long productId)
{
    Product product=AProductProvider.Instance.GetProduct(productId);
    ViewBag.PageTitle=product.Name; //Doesn't work

    return View(product);
}

1 个答案:

答案 0 :(得分:5)

您可以使用ControllerContext.ParentActionViewContext检索有关父视图的信息:

[OutputCache(Duration = 300)]
[ChildActionOnly]
public ActionResult ProductPartial(long productId)
{
    Product product = AProductProvider.Instance.GetProduct(productId);
    ControllerContext.ParentActionViewContext.ViewBag.PageTitle = product.Name;

    return View(product);
}

更新:要使其正常工作,您必须在父视图中调用ViewData,如下所示:

@ViewContext.ViewData["PageTitle"]

原因有点模糊。子操作接收对父操作的ViewData(对象的相同实例)的正确引用,但每个视图(ViewPage)都会在状态中接收ViewData的 copy 原始ViewData在Sytem.Web.Mvc.Html.TemplateHelpers.TemplateHelper方法的视图初始化期间有。在调用子操作发生之前,将初始化/复制父页面的ViewData,因此以后的子操作更新不适用。这是MVC的源代码:

// ....
ViewDataDictionary viewData = new ViewDataDictionary(html.ViewDataContainer.ViewData)
{
    Model = metadata.Model,
    ModelMetadata = metadata,
    TemplateInfo = new TemplateInfo
    {
        FormattedModelValue = formattedModelValue,
        HtmlFieldPrefix = html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName),
        VisitedObjects = new HashSet<object>(html.ViewContext.ViewData.TemplateInfo.VisitedObjects), // DDB #224750
    }
};

但是,ViewContext会保留引用,而不是复制到Controller上下文数据,因此您可以使用该引用。另一方面,如果你使用ViewContext.ViewData,你必须知道视图,子动作,部分,布局的执行顺序......