1

Update: It seems I was trying to set the ViewBag content in a partial view instead in a plain view, MVC3 makes it very easy to do this. I'm still interested why it doesn't work for partial views, i.e. why isn't the viewbag shared with partial views.

I'm trying to pass some data from a partial view to the layout view by using ViewData/ViewBag

// Used in the partial view
public static void RequireAssets(this HtmlHelper helper, params Asset[] assets)
{
    var alreadyRequired = helper.ViewData["RequiredAssets"] as List<Asset>;
    if (alreadyRequired == null)
    {
        alreadyRequired = new List<Asset>();            
        helper.ViewData.Add("RequiredAssets", alreadyRequired);
    }

    foreach (var asset in assets.Where(anAsset => !alreadyRequired.Contains(anAsset)))
        alreadyRequired.Add(asset);
}

// Used in the layout view
public static MvcHtmlString RenderAssetStyles(this HtmlHelper helper)
{
    var requiredAssets = helper.ViewData["RequiredAssets"] as List<Asset>;
    return requiredAssets == null ? null : GetStyleSheets(requiredAssets.Select(e => new StyleSheet(e)).ToArray());
}

public static MvcHtmlString RenderAssetScripts(this HtmlHelper helper)
{
    var requiredAssets = helper.ViewData["RequiredAssets"] as List<Asset>;
    return requiredAssets == null ? null : GetScripts(requiredAssets.Select(e => new Script(e)).ToArray());
}

The problem is that when RenderAssetStyles/Scripts is fired in the layout view the ViewData does not contain the key "RequiredAssets"

Usage

_Layout.cshtml:

<title>@ViewBag.Title</title>    
@Html.RenderAssetStyles()

PartialView.cshtml:

@{ 
    Html.RequireAssets(Assets.Grid, Assets.FileUpload); 
}
Boris B.
  • 4,933
  • 1
  • 28
  • 59

2 Answers2

1

Think you doing something wrong. Can't reproduced you effort. Try to check - are your View use exact this layout. It all it's ok try to create simple example which will be reproducible.

Ph0en1x
  • 9,943
  • 8
  • 48
  • 97
1

I could not reproduce this. I had to simplify your code and make some assumptions. But the following worked fine for me.

_Layout.cshtml

@using MyProject.Helpers
<title>@ViewBag.Title</title>    
@Html.RenderAssetStyles()
@Html.RenderAssetScripts()
@RenderBody()

View.cshtml

@using MyProject.Helpers
@{ 
    ViewBag.Title = "View";
    Html.RequireAssets(Asset.Grid, Asset.FileUpload);
    Layout = "~/Views/Shared/_Layout.cshtml";
}

Helpers.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MyProject.Helpers
{
    public enum Asset
    {
        Grid=1,
        FileUpload=2
    }
    public static class Helper
    {

        public static void RequireAssets(this HtmlHelper helper, params Asset[] assets)
        {
            var alreadyRequired = helper.ViewData["RequiredAssets"] as List<Asset>;
            if (alreadyRequired == null)
            {
                alreadyRequired = new List<Asset>();
                helper.ViewData.Add("RequiredAssets", alreadyRequired);
            }

            foreach (var asset in assets.Where(anAsset => !alreadyRequired.Contains(anAsset)))
                alreadyRequired.Add(asset);
        }

        // Used in the layout view
        public static MvcHtmlString RenderAssetStyles(this HtmlHelper helper)
        {
            var requiredAssets = helper.ViewData["RequiredAssets"] as List<Asset>;
            return requiredAssets == null ? null : MvcHtmlString.Create("Test Style");
        }

        public static MvcHtmlString RenderAssetScripts(this HtmlHelper helper)
        {
            var requiredAssets = helper.ViewData["RequiredAssets"] as List<Asset>;
            return requiredAssets == null ? null : MvcHtmlString.Create("Test Script");
        }
    }

}
Kaizen Programmer
  • 3,798
  • 1
  • 14
  • 30
  • I would try breaking at the RequireAssets helper, and then each of the MvcHtmlStrings to check the order they are being called. The only 'reproduction' I could achieve was to have everything in one .cshtml in which case if you have the RequireAssets called after the RenderAssetStyles/RenderAssetScripts you won't have any assets set, before the calls that require them. – Kaizen Programmer Apr 17 '12 at 15:16
  • It seems I was rendering the view as partial, I've updated the question. – Boris B. Apr 20 '12 at 14:33
  • http://stackoverflow.com/questions/4974027/modifying-mvc-3-viewbag-in-a-partial-view-does-not-persist-to-the-layout-cshtml may help – Kaizen Programmer Apr 20 '12 at 21:24