1
votes

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); 
}
2

2 Answers

1
votes

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");
        }
    }

}
1
votes

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.