27.10.09

Cómo invocar un archivo CSS incrustado en ASP.NET

Recientemente me vi en la necesidad de crear un componente a medida (control web). Se trataba de un TextBox que pudiese controlar distintos tipos de datos (números, fechas, textos con limitaciones, etc). Ninguno de los freeware me convencía, por lo que puse manos a la obra y lo comencé a escribir desde mi poco conocimiento actual sobre el tema.

El objeto en cuestión se encuentra en una .dll, junto con tres archivos Javascript y un archivo CSS. Hasta ahí todo fenómeno. Los archivos .js se deben incluir en la página dependiendo del tipo de validación que se necesite y el .css cuando el control necesite mostrar un calendario para que el usuario ingrese una fecha de forma más cómoda.

La idea es que los archivos incrustado en la biblioteca de controles se invoquen mediante el etiquetado normal (<script> y <link>) y no volcar el código directamente en la página, puesto que en los sucesivos postback el servidor se vería obligado a transmitir todo ese código.

Como dijera, mi escaso conocimiento de la construcción de controles me llevó a leer toda la documentación posible y buscar en la web los ejemplos más claros. La mayoría de los ejemplos para invocar los .js decían más o menos así:

protected override void OnPreRender(EventArgs e) {
Page.ClientScript.RegisterClientScriptInclude("FunkyJavaScript",
Page.ClientScript.GetWebResourceUrl(this.GetType(),
  "FunkyTextBox.Funky.js"));

base.OnPreRender(e);
}
Esto funciona correctamente para los .js, especialmente cuando se colocan varios controles del mismo tipo. Para el caso de los .css el código aconsejado en varios ejemplos es este:
string includeTemplate =
"<link rel='stylesheet' text='text/css' href='{0}' />";
string includeLocation =
Page.ClientScript.GetWebResourceUrl(this.GetType(), "myStylesheet _Links.css");
LiteralControl include =
new LiteralControl(String.Format(includeTemplate, includeLocation));
((HtmlControls.HtmlHead) Page.Header).Controls.Add(include);

Si leemos el código, lo que hace es agregar una etiqueta LINK al encabezado de la página enlazando el archivo incrustado. Lo problemático de esto es que si agregas tres controles, este código agregará tres etiquetas LINK. Y eso no es lo que queremos!!

Bueno... toda esta cháchara para explicarles con que bobada lo resolví y tal vez le sirva. También puede pasar que haya una mejor forma y que yo quede como un idiota ignorante. :-)

If Page.Header.FindControl("mcTextBoxCalendarCSS") Is Nothing Then
Dim lnkCss As New HtmlControls.HtmlLink
With lnkCss
.Attributes("rel") = "stylesheet"
.Attributes("text") = "text/css"
.ID = "mcTextBoxCalendarCSS"
.Href = Page.ClientScript.GetWebResourceUrl(Me.GetType(), "mcTextBoxCalendar.css")
 End With
Page.Header.Controls.Add(lnkCss)
End If

Lo que hace este código es simple, crea el mismo enlace, pero le pone un ID y si ya existe de un objeto anterior, no lo agrega. Simple, pero efectivo.