Изменение MVC 3 ViewBag в частичном представлении не сохраняется в _Layout.cshtml
Я использую MVC 3 с движком просмотра Razor. Я хочу установить некоторые значения в ViewBag внутри Partial View и хочу получить эти значения в моем _Layout.cshtml. Например, при настройке проекта ASP.NET MVC 3 по умолчанию вы получаете файл _Layout.cshtml в папке "/Views/Shared". В этом _Layout.cshtml заголовок страницы задается следующим образом:
<title>@ViewBag.PageTitle</title>
Затем в представлении "/Views/Home/About.cshtml" содержимое ViewBag изменяется:
@{
ViewBag.Title = "About Us";
}
Это прекрасно работает. Когда отображается представление About, заголовок страницы "О нас" . Итак, теперь я хочу отобразить частичный вид внутри своего представления About, и я хочу изменить ViewBag.Title внутри моего частичного представления. ( "/Views/Shared/SomePartial.cshtml" )
@Html.Partial("SomePartial")
В этом частичном представлении у меня есть этот код:
@{
ViewBag.Title = "About Us From The Partial View";
}
Когда я отлаживаю этот код, я вижу, что ViewBag.Title получает значение "О нас" , а затем в частичном представлении я вижу, что он получает reset в "О нас из частичного просмотра", но когда код попадает в _Layout.cshtml он возвращается к "О нас" .
Означает ли это, что если содержимое ViewBag будет изменено в частичном представлении, эти изменения не будут отображаться (быть доступными) в главном представлении (About.cshtml) или _Layout.cshtml?
Спасибо заранее!
Ответы
Ответ 1
У меня также была эта проблема, и я не мог найти четкое и очевидное решение.
Решение, с которым я столкнулся, состояло в том, чтобы реализовать метод расширения 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;
}
}
Он находит контроллер верхнего уровня для текущего запроса и возвращает тот же объект PageData каждый раз, когда метод вызывается в рамках одного и того же HTTP-запроса. Он создает новый объект PageData при первом вызове в новом HTTP-запросе.
Ответ 2
Если вы передадите ViewBag в частичный viewdatadictionary, затем вытащите его (и произведите), вы сможете делать все, что хотите, и эта ссылка сохраняется. Классная часть состоит в том, что, поскольку она динамична, вы можете даже добавить свойства, а затем они появятся на родительской странице Viewbag.
Page:
//set the viewbag into the partial view data
@{Html.RenderPartial("Elaborate", Model, new ViewDataDictionary { {"vb", ViewBag}});}
Частичная:
@{
var vb = ((dynamic)ViewData["vb"]);
vb.TheTitle = "New values";
}
Страница
@ViewBag.TheTitle = "New value"
Ответ 3
Частичный вид получает свой собственный ViewBag
.
Вы можете получить страницу ViewBag с ((WebViewPage) WebPageContext.Current.Page).ViewBag
Ответ 4
Вы можете сделать этот трюк в частичном представлении, чтобы переопределить заголовок в _Layout.cshtml:
@{
ViewBag.Title = "About Us From The Partial View";
}
......
<script type="text/javascript">
document.title = "@ViewBag.Title";
</script>
Ответ 5
Как указывали другие, Макет, Представления и Частицы получают свой собственный ViewBag. Однако я смог заставить его работать со следующим:
В представлении или частичном.
@{ Html.ViewContext.ViewBag.Title = "Reusable Global Variable"; }
Затем в _Layout
@Html.ViewContext.ViewBag.Title
Явным образом используя ViewContext, представления "повторно используют" тот же ViewBag.
Ответ 6
попробуйте код @SLaks с помощью
(((WebViewPage) WebPageContext.Current.Page).ViewBag).PropertyName
Ответ 7
Я пробовал следующее и работает:
В представлении (родительский)...
@Html.Partial("SomePartial", ViewData, null)
Примечание: ViewData
передается как аргумент model
, но вы должны указать null
для аргумента ViewData
для использования правильной перегрузки. Вы не можете использовать ViewBag
, потому что Html.Partial
не любит динамику.
Затем в частичном виде...
@model ViewDataDictionary
@{
Model["Title"] = "About us from the partial view";
}
Конечно, если вам нужно использовать аргумент model
для реальной модели, вам нужно быть более творческим.
Ответ 8
Если кто-то все еще ищет решение, похоже, вы можете сделать это с помощью TempData:
TempData["x"] = x;
TempData сохраняется до тех пор, пока она не будет прочитана, поэтому вы можете просто прочитать ее в своем _Layout. Вам просто нужно быть осторожным, чтобы вы все прочитали, чтобы он был очищен для следующего запроса.
Ответ 9
Я столкнулся с той же проблемой, когда я использую mvc3, и обнаружил, что
this.ViewBag.ViewBag.PropertyName
работает в вашем пользовательском элементе управления.
Ответ 10
Это то, для чего предназначены данные страницы. Поместите это в свое мнение.
@Page.somePropertyName = "Whatever you want";
И затем получите доступ к нему в вашем макете. Обязательно проверьте, чтобы он был не первым.
@{
if(Page.somePropertyName != null)
{
//Do stuff
}
}