Reputation:
I am writing a bit of code to add a link tag to the head tag in the code behind... i.e.
HtmlGenericControl css = new HtmlGenericControl("link");
css.Attributes["rel"] = "Stylesheet";
css.Attributes["type"] = "text/css";
css.Attributes["href"] = String.Format("/Assets/CSS/{0}", cssFile);
to try and achieve something like...
<link rel="Stylesheet" type="text/css" href="/CSS/Blah.css" />
I am using the HtmlGenericControl to achieve this... the issue I am having is that the control ultimatly gets rendered as...
<link rel="Stylesheet" type="text/css" href="/CSS/Blah.css"></link>
I cant seem to find what I am missing to not render the additional </link>
, I assumed it should be a property on the object.
Am I missing something or is this just not possible with this control?
Upvotes: 10
Views: 6100
Reputation: 651
The slightly hacky way.
This is page / control specific and does not require any overrides. So it has minimal impact on the rest of your system.
<asp:PlaceHolder ID="myPlaceHolder" runat="server">
<hr id="someElement" runat="server" />
</asp:PlaceHolder>
protected void Page_Init(object sender, EventArgs e)
{
myPlaceHolder.SetRenderMethodDelegate(ClosingRenderMethod);
}
protected void ClosingRenderMethod(HtmlTextWriter output, Control container)
{
var voidTags = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase) { "br", "hr", "link", "img" };
foreach (Control child in container.Controls)
{
var generic = child as HtmlGenericControl;
if (generic != null && voidTags.Contains(generic.TagName))
{
output.WriteBeginTag(generic.TagName);
output.WriteAttribute("id", generic.ClientID);
generic.Attributes.Render(output);
output.Write(HtmlTextWriter.SelfClosingTagEnd);
}
else
{
child.RenderControl(output);
}
}
}
Upvotes: 0
Reputation: 373
While trying to write a workaround for umbraco.library:RegisterStyleSheetFile(string key, string url)
I ended up with the same question as the OP and found the following.
According to the specs, the link tag is a void element. It cannot have any content, but can be self closing. The W3C validator did not validate <link></link>
as correct html5.
Apparently
HtmlGenericControl css = new HtmlGenericControl("link");
is rendered by default as <link></link>
. Using the specific control for the link tag solved my problem:
HtmlLink css = new HtmlLink();
It produces the mark-up <link/>
which was validated as correct xhtml and html5.
In addition to link, System.Web.UI.HtmlControls contains classes for other void element controls, such as img, input and meta.
Upvotes: 9
Reputation: 3409
I just created a solution for this, based on Ragaraths comments in another forum:
http://forums.asp.net/p/1537143/3737667.aspx
Override the HtmlGenericControl with this
protected override void Render(HtmlTextWriter writer)
{
if (this.Controls.Count > 0)
base.Render(writer); // render in normal way
else
{
writer.Write(HtmlTextWriter.TagLeftChar + this.TagName); // render opening tag
Attributes.Render(writer); // Add the attributes.
writer.Write(HtmlTextWriter.SelfClosingTagEnd); // render closing tag
}
writer.Write(Environment.NewLine); // make it one per line
}
Upvotes: 0
Reputation: 22836
Alternatively you can use Page.ParseControl(string)
, which gives you a control with the same contents as the string you pass.
I'm actually doing this exact same thing in my current project. Of course it requires a reference to the current page, (the handler), but that shouldn't pose any problems.
The only caveat in this method, as I see it, is that you don't get any "OO"-approach for creating your control (eg. control.Attributes.Add("href", theValue")
etc.)
Upvotes: 1
Reputation: 4426
I think you'd have to derive from HtmlGenericControl
, and override the Render
method.
You'll then be able to write out the "/>" yourself (or you can use HtmlTextWriter's SelfClosingTagEnd
constant).
Edit: Here's an example (in VB)
Upvotes: 11