it-swarm-ru.tech

Изменение MVB 3 ViewBag в частичном представлении не сохраняется в _Layout.cshtml

Я использую 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?

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

41
Zoran

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

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

12
Chris

Если вы передадите 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"
31
Tony Basallo

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

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

8
SLaks

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

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

......

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

Как уже указывали другие Layout , Views и Partials получают свои собственные ViewBag. Тем не менее, я смог заставить его работать со следующим: В представлении или частично.

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

Тогда в _Layout

@ Html.ViewContext.ViewBag.Title

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

4
Dax70

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

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

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

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

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

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

Тогда в частичном виде ...

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

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

1
Moose Factory

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

TempData["x"] = x;

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

0
chris