Agregue archivos CSS o JavaScript al encabezado del diseño desde vistas o vistas parciales

Página de diseño:

   

Una vista (AnotherView) de la aplicación necesita:

  

y AnotherView tiene una vista parcial (AnotherPartial) que necesita:

  

Pregunta: ¿Cómo podemos agregar estos archivos CSS enlaces enlaces AnotherView y AnotherPartial a la cabeza de diseño ?

RenderSection no es una buena idea porque AnotherPage puede tener más de un parcial. Agregar todo el CSS a la cabecera no es útil porque cambiará dinámicamente (depende de Anotherpages).

Diseño:

    @ViewBag.Title    @if (IsSectionDefined("AddToHead")) { @RenderSection("AddToHead", required: false) } @RenderSection("AddToHeadAnotherWay", required: false)  

Ver:

 @model ProjectsExt.Models.DirectoryObject @section AddToHead{  } 

Actualización : ejemplo básico disponible en https://github.com/speier/mvcassetshelper

Estamos utilizando la siguiente implementación para agregar archivos JS y CSS a la página de diseño.

Ver o Vista parcial:

 @{ Html.Assets().Styles.Add("/Dashboard/Content/Dashboard.css"); Html.Assets().Scripts.Add("/Dashboard/Scripts/Dashboard.js"); } 

Página de diseño:

  @Html.Assets().Styles.Render()   ... @Html.Assets().Scripts.Render()  

Extensión HtmlHelper:

 public static class HtmlHelperExtensions { public static AssetsHelper Assets(this HtmlHelper htmlHelper) { return AssetsHelper.GetInstance(htmlHelper); } } public class AssetsHelper { public static AssetsHelper GetInstance(HtmlHelper htmlHelper) { var instanceKey = "AssetsHelperInstance"; var context = htmlHelper.ViewContext.HttpContext; if (context == null) return null; var assetsHelper = (AssetsHelper)context.Items[instanceKey]; if (assetsHelper == null) context.Items.Add(instanceKey, assetsHelper = new AssetsHelper()); return assetsHelper; } public ItemRegistrar Styles { get; private set; } public ItemRegistrar Scripts { get; private set; } public AssetsHelper() { Styles = new ItemRegistrar(ItemRegistrarFormatters.StyleFormat); Scripts = new ItemRegistrar(ItemRegistrarFormatters.ScriptFormat); } } public class ItemRegistrar { private readonly string _format; private readonly IList _items; public ItemRegistrar(string format) { _format = format; _items = new List(); } public ItemRegistrar Add(string url) { if (!_items.Contains(url)) _items.Add(url); return this; } public IHtmlString Render() { var sb = new StringBuilder(); foreach (var item in _items) { var fmt = string.Format(_format, item); sb.AppendLine(fmt); } return new HtmlString(sb.ToString()); } } public class ItemRegistrarFormatters { public const string StyleFormat = ""; public const string ScriptFormat = ""; } 

Tristemente, esto no es posible por defecto para usar la section como sugirió otro usuario, ya que una section solo está disponible para el child inmediato de una View .

Sin embargo, lo que funciona es implementar y redefinir la section en cada vista , lo que significa:

 section Head { @RenderSection("Head", false) } 

De esta forma, cada vista puede implementar una sección de cabecera, no solo los hijos inmediatos. Sin embargo, esto solo funciona en parte, especialmente con los parciales múltiples que comienzan los problemas (como ha mencionado en su pregunta).

Entonces, la única solución real a su problema es usar ViewBag . Lo mejor probablemente sería una colección separada (lista) para CSS y scripts. Para que esto funcione, debe asegurarse de que la List utilizada se inicialice antes de ejecutar cualquiera de las vistas. Luego puede hacer cosas como esta en la parte superior de cada vista / parcial (sin importar si el valor de Scripts o Styles es nulo:

 ViewBag.Scripts.Add("myscript.js"); ViewBag.Styles.Add("mystyle.css"); 

En el diseño, puede recorrer las colecciones y agregar estilos según los valores de la List .

 @foreach (var script in ViewBag.Scripts) {  } @foreach (var style in ViewBag.Styles) {  } 

Creo que es feo, pero es lo único que funciona.

****** ACTUALIZACIÓN **** Dado que comienza a ejecutar las vistas internas primero y se abre paso hacia el diseño y los estilos CSS están en cascada, es probable que tenga sentido revertir la lista de estilos a través de ViewBag.Styles.Reverse()

De esta forma, se agrega primero el estilo más externo, que está en línea con la forma en que las hojas de estilo CSS funcionan de todos modos.

Traté de resolver este problema.

Mi respuesta está aquí.

“DynamicHeader” – http://dynamicheader.codeplex.com/ , https://nuget.org/packages/DynamicHeader

Por ejemplo, _Layout.cshtml es:

  @Html.DynamicHeader()  ... 

Y puede registrar archivos .js y .css en “DynamicHeader” en cualquier lugar que desee.

Por ejemplo, el bloque de código en AnotherPartial.cshtm es:

 @{ DynamicHeader.AddSyleSheet("~/Content/themes/base/AnotherPartial.css"); DynamicHeader.AddScript("~/some/myscript.js"); } 

Entonces, finalmente el resultado HTML es:

     ... 

Tuve un problema similar y terminé aplicando la excelente respuesta de Kalman con el siguiente código (no del todo ordenado, pero podría decirse que es más expansible):

 namespace MvcHtmlHelpers { //http://stackoverflow.com/questions/5110028/add-css-or-js-files-to-layout-head-from-views-or-partial-views#5148224 public static partial class HtmlExtensions { public static AssetsHelper Assets(this HtmlHelper htmlHelper) { return AssetsHelper.GetInstance(htmlHelper); } } public enum BrowserType { Ie6=1,Ie7=2,Ie8=4,IeLegacy=7,W3cCompliant=8,All=15} public class AssetsHelper { public static AssetsHelper GetInstance(HtmlHelper htmlHelper) { var instanceKey = "AssetsHelperInstance"; var context = htmlHelper.ViewContext.HttpContext; if (context == null) {return null;} var assetsHelper = (AssetsHelper)context.Items[instanceKey]; if (assetsHelper == null){context.Items.Add(instanceKey, assetsHelper = new AssetsHelper(htmlHelper));} return assetsHelper; } private readonly List _styleRefs = new List(); public AssetsHelper AddStyle(string stylesheet) { _styleRefs.Add(stylesheet); return this; } private readonly List _scriptRefs = new List(); public AssetsHelper AddScript(string scriptfile) { _scriptRefs.Add(scriptfile); return this; } public IHtmlString RenderStyles() { ItemRegistrar styles = new ItemRegistrar(ItemRegistrarFormatters.StyleFormat,_urlHelper); styles.Add(Libraries.UsedStyles()); styles.Add(_styleRefs); return styles.Render(); } public IHtmlString RenderScripts() { ItemRegistrar scripts = new ItemRegistrar(ItemRegistrarFormatters.ScriptFormat, _urlHelper); scripts.Add(Libraries.UsedScripts()); scripts.Add(_scriptRefs); return scripts.Render(); } public LibraryRegistrar Libraries { get; private set; } private UrlHelper _urlHelper; public AssetsHelper(HtmlHelper htmlHelper) { _urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext); Libraries = new LibraryRegistrar(); } } public class LibraryRegistrar { public class Component { internal class HtmlReference { internal string Url { get; set; } internal BrowserType ServeTo { get; set; } } internal List Styles { get; private set; } internal List Scripts { get; private set; } internal List RequiredLibraries { get; private set; } public Component() { Styles = new List(); Scripts = new List(); RequiredLibraries = new List(); } public Component Requires(params string[] libraryNames) { foreach (var lib in libraryNames) { if (!RequiredLibraries.Contains(lib)) { RequiredLibraries.Add(lib); } } return this; } public Component AddStyle(string url, BrowserType serveTo = BrowserType.All) { Styles.Add(new HtmlReference { Url = url, ServeTo=serveTo }); return this; } public Component AddScript(string url, BrowserType serveTo = BrowserType.All) { Scripts.Add(new HtmlReference { Url = url, ServeTo = serveTo }); return this; } } private readonly Dictionary _allLibraries = new Dictionary(); private List _usedLibraries = new List(); internal IEnumerable UsedScripts() { SetOrder(); var returnVal = new List(); foreach (var key in _usedLibraries) { returnVal.AddRange(from s in _allLibraries[key].Scripts where IncludesCurrentBrowser(s.ServeTo) select s.Url); } return returnVal; } internal IEnumerable UsedStyles() { SetOrder(); var returnVal = new List(); foreach (var key in _usedLibraries) { returnVal.AddRange(from s in _allLibraries[key].Styles where IncludesCurrentBrowser(s.ServeTo) select s.Url); } return returnVal; } public void Uses(params string[] libraryNames) { foreach (var name in libraryNames) { if (!_usedLibraries.Contains(name)){_usedLibraries.Add(name);} } } public bool IsUsing(string libraryName) { SetOrder(); return _usedLibraries.Contains(libraryName); } private List WalkLibraryTree(List libraryNames) { var returnList = new List(libraryNames); int counter = 0; foreach (string libraryName in libraryNames) { WalkLibraryTree(libraryName, ref returnList, ref counter); } return returnList; } private void WalkLibraryTree(string libraryName, ref List libBuild, ref int counter) { if (counter++ > 1000) { throw new System.Exception("Dependancy library appears to be in infinate loop - please check for circular reference"); } Component library; if (!_allLibraries.TryGetValue(libraryName, out library)) { throw new KeyNotFoundException("Cannot find a definition for the required style/script library named: " + libraryName); } foreach (var childLibraryName in library.RequiredLibraries) { int childIndex = libBuild.IndexOf(childLibraryName); if (childIndex!=-1) { //child already exists, so move parent to position before child if it isn't before already int parentIndex = libBuild.LastIndexOf(libraryName); if (parentIndex>childIndex) { libBuild.RemoveAt(parentIndex); libBuild.Insert(childIndex, libraryName); } } else { libBuild.Add(childLibraryName); WalkLibraryTree(childLibraryName, ref libBuild, ref counter); } } return; } private bool _dependenciesExpanded; private void SetOrder() { if (_dependenciesExpanded){return;} _usedLibraries = WalkLibraryTree(_usedLibraries); _usedLibraries.Reverse(); _dependenciesExpanded = true; } public Component this[string index] { get { if (_allLibraries.ContainsKey(index)) { return _allLibraries[index]; } var newComponent = new Component(); _allLibraries.Add(index, newComponent); return newComponent; } } private BrowserType _requestingBrowser; private BrowserType RequestingBrowser { get { if (_requestingBrowser == 0) { var browser = HttpContext.Current.Request.Browser.Type; if (browser.Length > 2 && browser.Substring(0, 2) == "IE") { switch (browser[2]) { case '6': _requestingBrowser = BrowserType.Ie6; break; case '7': _requestingBrowser = BrowserType.Ie7; break; case '8': _requestingBrowser = BrowserType.Ie8; break; default: _requestingBrowser = BrowserType.W3cCompliant; break; } } else { _requestingBrowser = BrowserType.W3cCompliant; } } return _requestingBrowser; } } private bool IncludesCurrentBrowser(BrowserType browserType) { if (browserType == BrowserType.All) { return true; } return (browserType & RequestingBrowser) != 0; } } public class ItemRegistrar { private readonly string _format; private readonly List _items; private readonly UrlHelper _urlHelper; public ItemRegistrar(string format, UrlHelper urlHelper) { _format = format; _items = new List(); _urlHelper = urlHelper; } internal void Add(IEnumerable urls) { foreach (string url in urls) { Add(url); } } public ItemRegistrar Add(string url) { url = _urlHelper.Content(url); if (!_items.Contains(url)) { _items.Add( url); } return this; } public IHtmlString Render() { var sb = new StringBuilder(); foreach (var item in _items) { var fmt = string.Format(_format, item); sb.AppendLine(fmt); } return new HtmlString(sb.ToString()); } } public class ItemRegistrarFormatters { public const string StyleFormat = ""; public const string ScriptFormat = ""; } } 

El proyecto contiene un método estático AssignAllResources:

 assets.Libraries["jQuery"] .AddScript("~/Scripts/jquery-1.10.0.min.js", BrowserType.IeLegacy) .AddScript("~/Scripts//jquery-2.0.1.min.js",BrowserType.W3cCompliant); /* NOT HOSTED YET - CHECK SOON .AddScript("//ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js",BrowserType.W3cCompliant); */ assets.Libraries["jQueryUI"].Requires("jQuery") .AddScript("//ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js",BrowserType.Ie6) .AddStyle("//ajax.aspnetcdn.com/ajax/jquery.ui/1.9.2/themes/eggplant/jquery-ui.css",BrowserType.Ie6) .AddScript("//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js", ~BrowserType.Ie6) .AddStyle("//ajax.aspnetcdn.com/ajax/jquery.ui/1.10.3/themes/eggplant/jquery-ui.css", ~BrowserType.Ie6); assets.Libraries["TimePicker"].Requires("jQueryUI") .AddScript("~/Scripts/jquery-ui-sliderAccess.min.js") .AddScript("~/Scripts/jquery-ui-timepicker-addon-1.3.min.js") .AddStyle("~/Content/jQueryUI/jquery-ui-timepicker-addon.css"); assets.Libraries["Validation"].Requires("jQuery") .AddScript("//ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.min.js") .AddScript("~/Scripts/jquery.validate.unobtrusive.min.js") .AddScript("~/Scripts/mvcfoolproof.unobtrusive.min.js") .AddScript("~/Scripts/CustomClientValidation-1.0.0.min.js"); assets.Libraries["MyUtilityScripts"].Requires("jQuery") .AddScript("~/Scripts/GeneralOnLoad-1.0.0.min.js"); assets.Libraries["FormTools"].Requires("Validation", "MyUtilityScripts"); assets.Libraries["AjaxFormTools"].Requires("FormTools", "jQueryUI") .AddScript("~/Scripts/jquery.unobtrusive-ajax.min.js"); assets.Libraries["DataTables"].Requires("MyUtilityScripts") .AddScript("//ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.min.js") .AddStyle("//ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables.css") .AddStyle("//ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables_themeroller.css"); assets.Libraries["MvcDataTables"].Requires("DataTables", "jQueryUI") .AddScript("~/Scripts/jquery.dataTables.columnFilter.min.js"); assets.Libraries["DummyData"].Requires("MyUtilityScripts") .AddScript("~/Scripts/DummyData.js") .AddStyle("~/Content/DummyData.css"); 

en la página _layout

 @{ var assets = Html.Assets(); CurrentResources.AssignAllResources(assets); Html.Assets().RenderStyles() }  ... @Html.Assets().RenderScripts()  

y en el (los) parcial (es) y vistas

 Html.Assets().Libraries.Uses("DataTables"); Html.Assets().AddScript("~/Scripts/emailGridUtilities.js"); 

Puede definir la sección mediante el método RenderSection en el diseño.

Diseño

   @RenderSection("heads", required: false)  

Luego puede incluir sus archivos CSS en el área de la sección en su vista, excepto la vista parcial .

La sección funciona a la vista, pero no funciona en vista parcial por diseño .

  @section heads {  } 

Si realmente desea usar el área de sección en vista parcial, puede seguir el artículo para redefinir el método RenderSection.

Razor, diseños nesteds y secciones redefinidas – Marcin en ASP.NET

Pruebe la solución lista para usar (ASP.NET MVC 4 o posterior):

 @{ var bundle = BundleTable.Bundles.GetRegisteredBundles().First(b => b.Path == "~/js"); bundle.Include("~/Scripts/myFile.js"); } 

Para aquellos de nosotros que usamos ASP.NET MVC 4, esto puede ser útil.

Primero, agregué una clase BundleConfig en la carpeta App_Start.

Aquí está mi código que utilicé para crearlo:

 using System.Web.Optimization; public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/SiteMaster.css")); } } 

Segundo, registré la clase BundleConfig en el archivo Global.asax:

 protected void Application_Start() { BundleConfig.RegisterBundles(BundleTable.Bundles); } 

En tercer lugar, agregué ayudantes de estilo al mi archivo CSS:

 /* Styles for validation helpers */ .field-validation-error { color: red; font-weight: bold; } .field-validation-valid { display: none; } input.input-validation-error { border: 1px solid #e80c4d; } input[type="checkbox"].input-validation-error { border: 0 none; } .validation-summary-errors { color: #e80c4d; font-weight: bold; font-size: 1.1em; } .validation-summary-valid { display: none; } 

Finalmente utilicé esta syntax en cualquier Vista:

 @Styles.Render("~/Content/css") 

Aquí hay un complemento NuGet llamado Cassette , que entre otras cosas le proporciona la capacidad de referenciar scripts y estilos en parciales.

Aunque hay varias configuraciones disponibles para este complemento, lo que lo hace muy flexible. Esta es la forma más sencilla de remitir archivos de scripts o hojas de estilo:

 Bundles.Reference("scripts/app"); 

De acuerdo con la documentación :

Las llamadas a la Reference pueden aparecer en cualquier lugar de una página, diseño o vista parcial.

El argumento de ruta puede ser uno de los siguientes:

  • Un camino de paquete
  • Una ruta de activos: se hace referencia al paquete completo que contiene este activo
  • Una URL

Escribí un contenedor fácil que le permite registrar estilos y scripts en cada vista parcial de forma dinámica en la etiqueta de cabecera.

Está basado en el DynamicHeader jsakamoto up, pero tiene algunas mejoras de rendimiento y ajustes.

Es muy fácil de usar y versátil.

El uso:

 @{ DynamicHeader.AddStyleSheet("/Content/Css/footer.css", ResourceType.Layout); DynamicHeader.AddStyleSheet("/Content/Css/controls.css", ResourceType.Infrastructure); DynamicHeader.AddScript("/Content/Js/Controls.js", ResourceType.Infrastructure); DynamicHeader.AddStyleSheet("/Content/Css/homepage.css"); } 

Puede encontrar el código completo, explicaciones y ejemplos en el interior: Agregar estilos y secuencias de comandos dinámicamente a Head Tag