Steven Sproat
Steven Sproat

Reputation: 4578

Set ViewData inside a RenderPartial

I had previously been using TempData to set things like a "body css class", which then pages and partials could override.

I've now moved over to ViewData after realising that TempData uses sessions, however setting a ViewDataDictionary's value inside the partial basically gets ignored when it gets back up to the page - and never propagates up the layout hierarchy.

I've tried calling "RenderPartial" from inside my Page, and using the override which allows me to specify the ViewData to pass over:

Layout:

Page:

@{
    var cssClass = (ViewData["something"] != null) ? ViewData["something"].ToString() : "";
}

<body class="@cssClass">

Page:

@{
    ViewData["something"] = "blah";
    Html.RenderPartial("MyPartial", ViewData)
}

Partial:

@{
    ViewData["something"] += " blah";
}

When I debug inside my Layout, I can see that ViewData["something"] is "blah" - the partial didn't set it correctly.

When I was using TempData this would work ok. I don't really want to go back to using TempData because of ASP session locking and its effect on concurrent requests.

Has anybody got this to work before? Am I overlooking something?

Thanks

Upvotes: 0

Views: 889

Answers (2)

rism
rism

Reputation: 12142

So this is a one way propagation as you've discovered if you want to set data in partial and return to parent view you can use the HttpContext which is not very cool but it works:

Parent:

@{
    HttpContext.Current.Items["Something"] = "blah";
    Html.RenderPartial("_Partial");
}
@HttpContext.Current.Items["Something"];

Partial:

@{
    HttpContext.Current.Items["Something"] = "somethingelse";
}

Outputs "somethingelse" in the parent.

Alternatively and the way it's typically done, if you're bypassing TempData, is via the parent model or a temp model:

Model:

public class MyTempModel
{
    public string Something { get; set; }
}

Parent:

@{
    var tmod = new MyTemModel()
    {
       Something = "blah"
    };
    Html.RenderPartial("_Partial", tmod);
}
@tmod.Something;

Partial:

@model MyTempModel
@{
    tMod.Something = "somethingelse";
}

Outputs "somethingelse" in the parent.

Upvotes: 3

Chris Pratt
Chris Pratt

Reputation: 239350

Each view has its own ViewData. By default, Razor fills views further down the hierarchy with the ViewData of their parents, but this is one-way. For example, if you do something like:

SomeView.cshmtl

@{ ViewData["foo"] = "bar"; }
@Html.Partial("_SomePartial")

SomePartial.cshtml

@ViewData["foo"]

The result of the partial will be "bar" as you'd expect. But, if you did something like:

SomeView.cshtml

@Html.Partial("_SomePartial")
@ViewData["foo"]

_SomePartial.cshtml

@{ ViewData["foo"] = "bar"; }

Nothing would be printed, as ViewData["foo"] doesn't exist in the view data for the parent view, only in the view data for the partial.

Upvotes: 3

Related Questions