15

I've created a Visual Studio SharePoint 2010 solution with an ASCX that adds some JavaScript files and CSS to the head of each page; this is based on this article. When I deploy the solution, it adds the files to the correct server folder:

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\CustomPageHead

But then the files aren't added to the page headers. I've gone in and activated the user control from the site features but this hasn't fixed it. Here's the simple code in the CustomPageHead.ascx.cs file; I removed the JS files to see if that was causing the issue:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;

namespace CustomPageHead.CONTROLTEMPLATES
{
    public partial class CustomPageHead : UserControl
    {

        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected override void OnInit(EventArgs e)
        {

            Page.Init += delegate(object sender, EventArgs e_Init)
            {
                string SiteURL = SPContext.Current.Web.Url;

                Page.Header.Controls.Add(new LiteralControl(
            "<link rel=\"stylesheet\" type=\"text/css\" href=\""
            + SiteURL + "/_layouts/CustomPageHead/custom.css\" />"));

                Page.Header.Controls.Add(new LiteralControl(
            "<meta name=\"keywords\" content=\"sharepoint,c-sharp\" />"));
            };

            base.OnInit(e);
        }
    }
}

Could it be that I'm trying to activate the feature from a site such as http://mydomain.org/mysite/ and the path in the code above is looking at the current site's root? But why isn't it at least adding the control to the page, even if it has the wrong path?

  • Hi Alex, do you still have this solution? I am trying to apply something similar for SP 2013, but without luck. Could you please share the whole code with me? thank you – Pedro Sep 10 '18 at 12:17
  • @Pedro, sorry I’m not at that job anymore and don’t have the solution. If you post a new question and reference this post, someone might be able to help. Good luck – Alex C Sep 10 '18 at 12:23
22

As James mentioned, your main mistake is that you are using Page.Header.Controls. It is much simplier: this.Controls works like a charm.

If it will not work, you should then check your delegate control declaration XML code. It should look like this:

<Control Id="AdditionalPageHead" Sequence="1000" ControlSrc="~/_controltemplates/MyCompany/AdditionalPageHead.ascx" />

Lastly, I'd recommend you to use native SharePoint controls: CssRegistration and ScriptLink, instead of LiteralControl approach for this purpose.

For example, here is the working code:

    protected override void CreateChildControls()
    {
        base.CreateChildControls();

        this.Controls.Add(new ScriptLink()
            {
                Name = "/_layouts/MyCompany/MyScript.js",
                Language = "javascript",
                Localizable = false
            });

        this.Controls.Add(new CssRegistration()
            {
                Name = "/_layouts/MyCompany/MyStyles.css"
            });
    }

Btw, by using CssRegistration, you could hit the branding bonus, because this approach will allow you to use themable css files, like this:

    protected override void CreateChildControls()
    {
        base.CreateChildControls();
        this.Controls.Add(new CssRegistration() { Name = "/Style Library/Themable/MyCompany/MyStyles.css", EnableCssTheming = true });

    }
  • Thanks, omlin. The problem also was I had missed one of the steps in creating the solution as described in the article. Also, what does the base.CreateChildControls() do in the two method overrides above? – Alex C Sep 1 '11 at 8:51
  • 2
    Base method call it is not obligatory in this particular case, you can safely clear if off. Visual Studio generates it by default :) – Andrey Markeev Sep 1 '11 at 9:13
  • 2
    +1 for CssRegistration. It has an "After" property, where you specify the name of the CSS file after which you want yours to load. This lets you cascade the styles correctly and predictably. This property is new SP2010. – James Love Sep 1 '11 at 12:40
  • Thanks for your notice, James! Yep, using native controls often delivers some honey drops :) – Andrey Markeev Sep 1 '11 at 14:34
  • An interesting addition to this code: The Name = "_layouts...." is pulling the file implicitly based on the internal server path C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS, so you don't need to prepend the server path to it; it will blow up with an error Error: Cannot make a cache safe URL for … – Alex C Sep 20 '11 at 13:38
6

Hm.

What I would do is do the work in CreateChildControls. Have it just add the two LiteralControls to the this.Controls collection.

Then, add your ASCX to the AdditionalPageHead delegate control via your Feature. (step 33 in that article you linked to).

There is a reason (and at this time in the morning I can't remember what it is), but the Page.Header control never did add my controls for me. Add them to this.Controls and do it in CreateChildControls and it'll probably work fine.

This is the method I use to add CSS and jQuery libraries to all my branding projects.

  • Thanks, James. What's the diff between this.Controls and Page.Header.Controls? Is it a shortcut? I'm learning more and more by posting here and thanks to all the folks who reply, like yourself :) – Alex C Sep 1 '11 at 12:13

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.