Подтвердить что ты не робот

Изменение 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?

Спасибо заранее!

4b9b3361

Ответ 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
    }
}