Изменение MVC 3 ViewBag в частичном представлении не сохраняется в _Layout.cshtml - PullRequest
42 голосов
/ 12 февраля 2011

Я использую MVC 3 с движком Razor. Я хочу установить некоторые значения в ViewBag внутри частичного представления и хочу получить эти значения в моем _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 и хочу изменить ViewBag.Title внутри моего частичного представления. ( "/Views/Shared/SomePartial.cshtml")

@Html.Partial("SomePartial")

В этом Частичном представлении у меня есть этот код:

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

Когда я отлаживаю этот код, я вижу, что ViewBag.Title устанавливается в «О нас», а затем в представлении «Частично» я вижу, что он сбрасывается в «О нас из представления с частичным представлением», но когда код достигает _Layout. cshtml восходит к «О нас».

Означает ли это, что если содержимое ViewBag изменяется в частичном представлении, эти изменения не будут отображаться (быть доступными) в главном представлении (About.cshtml) или в _Layout.cshtml?

Заранее спасибо!

Ответы [ 10 ]

31 голосов
/ 02 марта 2011

Если вы передадите ViewBag в словарь viewdatictionary, а затем вытащите его (и преобразуете), вы можете делать все, что захотите, и ссылка сохраняется. Самое интересное в том, что, поскольку он динамический, вы даже можете добавить свойства, и тогда они будут отображаться в Viewbag родительской страницы.

Страница:

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

Частичное:

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

Страница

@ViewBag.TheTitle = "New value"
12 голосов
/ 13 февраля 2011

У меня тоже была эта проблема, и я не смог найти ни одного аккуратного и очевидного решения.

Решение, которое я придумал, состояло в том, чтобы реализовать метод расширения 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-запросе.

8 голосов
/ 12 февраля 2011

Частичное представление получает свой собственный ViewBag.

. Вы можете получить ViewBag страницы из ((WebViewPage) WebPageContext.Current.Page).ViewBag

7 голосов
/ 14 ноября 2012

Вы можете сделать этот трюк при частичном просмотре, чтобы переопределить заголовок в вашем _Layout.cshtml:

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

......

<script type="text/javascript">
    document.title = "@ViewBag.Title";
</script>
4 голосов
/ 12 июня 2012

Как отмечали другие Макет , Представления и Частицы получают свои ViewBag . Тем не менее, я смог заставить его работать со следующими: В представлении или частично.

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

Затем в _Layout

@Html.ViewContext.ViewBag.Title

Явно используя ViewContext , представления повторно используют один и тот же ViewBag.

1 голос
/ 14 января 2013

Я пробовал следующее, и оно работает:

В представлении (родительском) ...

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

Примечание: ViewData передается как аргумент model, но вы должны указать null для аргумента viewData, чтобы использовать правильную перегрузку.Вы не можете использовать ViewBag, потому что Html.Partial не любит динамику.

Затем в частичном представлении ...

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

Конечно, если вам нужно использоватьаргумент model для реальной модели, вам нужно быть более креативным.

1 голос
/ 07 июня 2011

попробуйте код @SLaks с

(((WebViewPage) WebPageContext.Current.Page).ViewBag).PropertyName
0 голосов
/ 09 мая 2017

Если кто-то все еще ищет решение этой проблемы, похоже, что вы можете сделать это с помощью TempData:

TempData["x"] = x;

TempData сохраняется до тех пор, пока он не будет прочитан, поэтому вы можете просто прочитать его в _Layout.Вам просто нужно быть осторожным, чтобы вы прочитали все, чтобы оно было очищено для следующего запроса.

0 голосов
/ 20 июня 2013

Я это то, для чего предназначены данные страницы. Поп это в вашем представлении.

@Page.somePropertyName = "Whatever you want";

А затем получите к нему доступ в виде макета. Убедитесь, что сначала он не равен нулю.

@{
    if(Page.somePropertyName != null)
    {
       //Do stuff
    }
}
0 голосов
/ 27 октября 2011

Я столкнулся с той же проблемой, когда использую mvc3, и обнаружил, что

this.ViewBag.ViewBag.PropertyName 

работает в вашем пользовательском контроле.

...