0

I'm writing an ASCX control that needs to reference both a JavaScript file and a CSS file.

Obviously, I only want the host page to reference these files once. So I'm using Page.ClientScript.RegisterClientScriptInclude() to reference the JavaScript file. The CSS file, however, is a bit more complicated.

I thought maybe I could do the following:

if (!Page.ClientScript.IsClientScriptIncludeRegistered(ScriptManagerJsKey))
{
    Page.ClientScript.RegisterClientScriptInclude(this.GetType(), ScriptManagerJsKey, ResolveClientUrl("~/javascript/PaymentSchedule.js"));

    HtmlLink cssLink = new HtmlLink();
    cssLink.Href = "~/css/PaymentSchedule.css";
    cssLink.Attributes["rel"] = "stylesheet";
    cssLink.Attributes["type"] = "text/css";
    Page.Header.Controls.Add(cssLink);
}

The idea here was to add an HtmlLink to reference the CSS file in the page header, but only once. Since I believe this code will only add the JavaScript reference once, I thought this would do the trick.

However, this actually adds the reference to the CSS file twice in the head section of the file.

Has anyone found a trick to referencing a CSS file only once from an ASCX control?

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • possible duplicate of [ASP.NET Custom Control - What is the best way to include embedded CSS reference only once?](http://stackoverflow.com/questions/3876601/asp-net-custom-control-what-is-the-best-way-to-include-embedded-css-reference) – Alexander Manekovskiy Dec 11 '14 at 10:10

3 Answers3

1

You can use HttpContext.Current.Items for this kind of stuff.

private void UserControl_Init(object sender, EventArgs e)
{
    this.addStyleSheet("~/css/PaymentSchedule.css");
}

private void addStyleSheet(String href)
{
    if (String.IsNullOrWhiteSpace(Convert.ToString(HttpContext.Current.Items[href])))
    {
        HttpContext.Current.Items[href] = href;
        HtmlLink sheet = new HtmlLink() {
            Href = href
        };
        sheet.Attributes["rel"] = "stylesheet";
        sheet.Attributes["type"] = "text/css";
        this.Page.Header.Controls.Add(sheet);
    }
}
cmd.prompt
  • 954
  • 7
  • 14
  • This is a nice suggestion. However, I decided to post a workaround I came up with this morning that doesn't require adding any data to the current context. – Jonathan Wood Dec 11 '14 at 19:08
0

Have you tried adding the attributes like this?

HtmlLink cssLink = new HtmlLink();
cssLink.Href = "~/css/PaymentSchedule.css";
cssLink.Attributes.Add("rel", "stylesheet");
cssLink.Attributes.Add("type", "text/css")
Page.Header.Controls.Add(cssLink);
Sean
  • 46
  • 3
  • Why? The rendered links are fine. The only issue is that links are rendered on the page for every instance of my control. – Jonathan Wood Dec 10 '14 at 20:29
  • Ah sorry I misread your question. You can actually specify the control to add the element to, if you know the index. 'Page.Header.Controls[0].Add(cssLink);' – Sean Dec 10 '14 at 20:58
  • I don't follow you. Do you understand the issue I'm having? How would this help? – Jonathan Wood Dec 10 '14 at 21:23
0

I'm not sure why my original code shouldn't work. It seems like IsClientScriptIncludeRegistered() should prevent the code within my if statement from running more than once.

At any rate, here's how I worked around it:

private static readonly string ScriptManagerJsKey = "PaymentScheduleControls.ascx.js";
private static readonly string CssLinkId = "PaymentScheduleControlCssLink";

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.ClientScript.IsClientScriptIncludeRegistered(ScriptManagerJsKey))
    {
        Page.ClientScript.RegisterClientScriptInclude(this.GetType(), ScriptManagerJsKey, ResolveClientUrl("~/javascript/PaymentSchedule.js"));
        if (Page.Header.FindControl(CssLinkId) == null)
        {
            HtmlLink cssLink = new HtmlLink();
            cssLink.ID = CssLinkId;
            cssLink.Href = "~/css/PaymentSchedule.css";
            cssLink.Attributes["rel"] = "stylesheet";
            cssLink.Attributes["type"] = "text/css";
            Page.Header.Controls.Add(cssLink);
        }
    }
}

This code simply sets an explicit ID for the CSS link control. It then takes steps to only add the link if it isn't already added. Seems to work okay.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466