miércoles, 27 de abril de 2011

Espacios en blanco en HTML

Hoy toca de hablar de los espacios en blanco en documentos HTML.

Lo cierto es que, aunque este tema puede parecer algo trivial, estoy seguro de que más de uno no tiene 100% claro cómo funcionan exactamente este tema (incluido yo).

Lo primero que hay que aclarar es que HTML tratará de igual forma una serie de caracteres que para él son todos lo mismo, es decir, tanto un espacio en blanco como un tabulador, un retorno de carro o una nueva línea, todos ellos tienen el mismo tratamiento… son ignorados!

El comportamiento predeterminado de HTML es ignorar cualquiera de esos caracteres, es decir, no trabaja con los espacios sobrantes (lógicamente queda fuera de ese tratamiento el espacio en blanco que separa palabras).

De este modo, podemos escribir un código HTML como el siguiente (donde hay espacios, tabuladores, nuevas líneas, etc.) y observar como se ve en el navegador

clip_image001

clip_image003

El resultado no hace sino afirmar que HTML ignora los espacios en blanco.

Si lo queremos es solucionar el problema de nuevas líneas, HTML nos ofrece la etiqueta <br> (<br /> en XHTML). Esta etiqueta fuerza al navegador a insertar una nueva línea, pero fíjate como esto sigue sin afectar a los tabuladores y espacios en blanco.

clip_image004

clip_image005

Para los espacios en blanco sobrantes, de nuevo HTML nos da una solución. Esta vez tendremos que utilizar la entidad HTML &nbsp;. Esta entidad fuerza al navegador a mostrar un espacio en blanco (fíjate que para separar palabras no es necesario porque ese es el único espacio en blanco que HTML trata de forma automática). Por ejemplo:

clip_image006

clip_image007

Como curiosidad te puedo decir que &nbsp; significa NonBreakingSpace y que además de forzar al navegador a mostrar espacios en blanco, tiene otro efecto no tan obvio y es que fuerza al navegador a no partir los textos. Es decir, si yo escribo en HTML “Sergio”, jamás veré “Ser” en una línea y “gio” en otra (esto de cajón, ¿Quién se cree HTML para partir mí nombre?).

Pues bien, si escribo “Sergio&nbsp;León” pasará exactamente lo mismo, siempre veré Sergio seguido de León. Un momento… ¡Entonces esto significa que nunca mi apellido se mostrará en una nueva línea! ¿Era esto lo que quería? Lo cuento así porque lo que intento evitar es la “sobredosis de &nbsp;” (que te juro existe y puede ser un dolor de cabeza). De hecho, si lo que quieres es que no se parta el texto, lo que debería utilizar es la propiedad white-space y el valor nowrap.

Finalmente, la conclusión a la que llegamos es que da igual como luzca nuestro código  HTML (en lo relativo a espacios en blanco), porque después el navegador lo interpretará como es menester. Y que además tenemos que tener cuidado con &nbsp; porque recuerda: “es un espacio en blanco no divisible”.

Un saludo!

Videos imprescindibles (OFF-TOPIC)


Unos enlaces a videos “must-watch”, que luego los pierdo!

http://www.youtube.com/watch?v=EPNjWWQqWCA&feature=player_embedded

http://www.youtube.com/watch?v=ZSbP1oRbA1Y&feature=fvsr

http://www.youtube.com/watch?v=13A0_QkqtaQ

Un saludo.

martes, 19 de abril de 2011

Session en web garden


En un post anterior vimos a vista de pájaro cuales eran las
diferencias entre un web garden y un web farm.

Lo cierto es que ese post era totalmente teórico y ahora me gustaría que en este post viéramos realmente como implementar ambas soluciones.

La necesidad surge porque cualquier proyecto que pretenda ser escalable y tolerante a fallos, necesitará antes o después poder ser desplegado sin problemas en entornos de granjas web. Es decir, no se puede querer ganar escalabilidad y redundancia metiendo más máquinas si nuestro código no está preparado para trabajar en estos escenarios de despliegue.

El mayor problema que vamos a encontrar tanto en un web garden como en un web farm es que ambos trabajan en su propio y aislado espacio de memoria. Esto significa que los objetos Application, Session y Cache son independientes unos de otros. Es decir, los datos almacenados en la sesión de la máquina A no son los mismos que los almacenados en la sesión de la máquina B.

Lo cierto es que para el objeto Session (para Application y Cache habría que buscar soluciones alternativas), la solución pasa por guardarlo en base de datos. De este modo, el objeto Session será compartida por todas las máquinas en un web farm o procesadores en el caso de un web garden. Además y como característica extrá un reinicio de la aplicación no supondrá que se pierdan los datos de sesión. Para guardar la sesión en base de datos, la principal consideración es que todo lo que queremos guardar tiene que ser serializable.

Antes de ver cómo guardar la sesión en base de datos, veamos primero el problema y así seremos conscientes de que existe.

Nuestro ejemplo será una página sencilla donde podremos incrementar un valor tanto para Application, como para Session y Cache. Como vamos a empezar por un web garden, también mostraremos en pantalla el PID del IIS Worker Process que está atiendo actualmente nuestra petición.

Para crear un web garden hay que incrementar el número de IIS Worker Process que atienden al grupo de aplicaciones (application pool) en el que se ejecuta nuestra aplicación. Seguro que habrá más opciones relativas a un web garden que se puedan configurar pero inicialmente sólo con esto ya serviría al propósito de este post.

clip_image002

Si ahora ejecutamos nuestra aplicación veremos cuales son los resultados.

A este respecto cabe mencionar que no he encontrado ninguna pauta concreta sobre cuando IIS atiende una petición en un proceso o en otro. De hecho, a veces en mi misma máquina sólo utilizó un proceso, después dos, si un compañero también pedía la página desde su máquina le atendía desde otro proceso, etc.

En cualquier caso (y después de haber hecho clic 100 veces de forma compulsiva) los resultados son los siguientes:

clip_image003

clip_image004

clip_image005

Como vemos, hay 2 procesos con distinto PID atendiendo la misma aplicación. Además vemos como los valores de Application, Session y Cache son distintos en ambos. Está claro que tenemos un problema si queremos desplegar nuestra aplicación en un entorno de web garden y utilizar Application, Session o Cache.

El primer problema que vamos a solucionar es el objeto Session (y de hecho el único que trataremos en este post). Para ello, vamos a guardar la sesión en base de datos (también sería igualmente válido guardar la sesión en un servidor de estado). En cualquiera de los casos la sesión será compartida por múltiples procesos (web garden) o incluso máquinas (web farm) y además no se perderá si se reinicia la aplicación.

Para más información sobre las distintas opciones disponible para guardar el objeto Session, puedes visitar http://msdn.microsoft.com/es-es/library/ms178586(v=vs.80).aspx y http://support.microsoft.com/kb/317604/EN-US

Para guardar la sesión en base de datos lo primero que necesitamos es una estructura de tablas adecuada. Para ello primero he creado una base de datos llamada “EjemploWebFarm” y después ejecutaremos el siguiente comando:

aspnet_regsql.exe –S NombreServidor –U NombreUsuario –P Password –ssadd –sstype c –d EjemploWebFarm

clip_image007

A grandes rasgos le hemos dicho que cree todos los objetos necesarios (tablas, procedimientos almacenados, etc.) en nuestra base de datos “EjemploWebFarm”.

También se puede guardar en la base de datos tempdb (pero se perdería la sesión si se reinicia el servidor SQL) o en la base de datos ASPState (imagina que tienes varias aplicaciones utilizando este sistema en un mismo servidor y quieres agrupar a todas ellas en una sola base de datos).

Nosotros hemos optado por la tercera vía que es utilizar nuestra propia base de datos.

La verdad es que nos ha metido un buen número de procedimientos almacenados, tipos definidos por el usuario y un par de tablas: ASPStateTempApplications y ASPStateTempSessions.

Teniendo ya el soporte donde guardar la sesión sólo queda configurar nuestro fichero web.config para indicar que queremos guardar allí el objeto Session. Esto se consigue a través del elemento sessionState.

<?xml version="1.0"?>

<configuration>

  <system.web>

    <compilation debug="false" strict="false" explicit="true" targetFramework="4.0"/>

    <sessionState

      allowCustomSqlDatabase="true"

      mode="SQLServer"

      sqlConnectionString="Data Source=LOBEZNO;Initial Catalog=EjemploWebFarm;Persist Security Info=True;User ID=sa;Password=********"/>

  </system.web>

</configuration>

Si ahora ejecutamos de nuevo nuestra aplicación podemos ver que el objeto Session ya está compartido entre los distintos IIS Worker Process de nuestro web garden. Por otro lado, si vemos el contenido de las tablas podemos observar que en ASPStateTempApplications ha metido 1 registro con el campo AppName a la ruta de IIS que identifica nuestra aplicación.

clip_image008

Y que en ASPStateTempSessions ha metido 1 registro cuyo campo SessionId es el mismo valor que vemos en la cookie ASP.NET_SessionId. Es así como se sabe que valores de sesión guardados en esta tabla corresponden con que sesiones en concreto.

Si por algún motivo no tenemos un MS SQL Server disponible para guardar la sesión también podemos utilizar un servidor de estado. Esta opción es igualmente considera fuera de proceso (out of proccess), por lo que nuestros datos de sesión también serán compartidos en entornos de multi-procesador o multi-servidor.

Al instalar ASP.NET se instala un servidor de estado como un servicio (por defecto está detenido). En concreto es el fichero aspnet_state.exe quien da el servicio. Los cambios para guardar nuestra sesión en este servidor son mínimos y todos ellos a través del fichero web.config, que ahora queda de la siguiente forma:

<?xml version="1.0"?>

<configuration>

  <system.web>

    <compilation debug="true" strict="false" explicit="true" targetFramework="4.0"/>

    <sessionState

      mode="StateServer"

      sqlConnectionString="tcpip=LOBEZNO:42424"/>

  </system.web>

</configuration>

 

Lógicamente también tenemos que iniciar el servicio pertinente:

clip_image010

Si ejecutamos de nuevo nuestra aplicación  el resultado es el deseado, es decir, se están compartiendo los datos de sesión.

Queda pendiente como solucionar los objetos Application y Cache, pero eso será otro día.

Un saludo!.

lunes, 18 de abril de 2011

Buenas prácticas CSS

Después de haber escrito una serie de post sobre CSS, creo que es interesante hacer un pequeño resumen sobre buenas prácticas en CSS.

Probablemente vaya actualizando este post con la experiencia que del trabajo del día a día, pero hoy voy a comenzar con lo siguiente:

  • Todos los documentos tienen que incluir una directiva DOCTYPE. Si quieres saber más, visita DOCTYPE, quirk, strict y un poco más.
  • Evita en la medida de lo posible, el atributo style (estilos incrustados en el elemento) que como ya sabemos se pasan la especificidad por el forro de los …
  • Además y sobre la especificad, usa los selectores justos y necesarios. Hay que llegar a seleccionar el o los elementos deseados, utilizando el selector mínimo y menos generalista.
  • Resetea los estilos del navegador para intentar tener un diseño cross-browser.
  • Utiliza minúsculas tanto para los nombres, propiedades y valores de una regla css. Esto se recomienda porque parece que algunos navegadores antiguos tienen problemas con las mayúsculas.
  • Si tienes que separar palabras en el nombre de un selector, utiliza el guión en vez del guión bajo. De igual modo, parece que algunos navegadores antiguos tienen problemas con el guión bajo.
  • Los nombres de los selectores tienen que tener un significado relativo al contenido y no a su disposición o estructura. Es decir, mejor “barra-navegacion” que “izquierda”, porque ¿Qué pasa si mañana la izquierda es derecha?
  • Si tienes alternativa, evita el uso de hacks. Para intentarlo lo mejor es diseñar en la última versión del navegador de turno (que será la que mejor soporte los estándares actuales) y después ver cómo queda en versiones anteriores del mismo navegador. Si inviertes los términos y en vez de partir de un código estándar hacía un código un poco más personalizado, es al revés, entonces seguro que tienes millones de hacks.
  • La mitad de los hacks que vas a necesitar son para IE y en ese caso yo particularmente prefiero utilizar los comentarios condicionales para IE que funcionan de maravilla.
  • Ordena las propiedades de una regla siempre del mismo modo. Es decir, si prefieres en orden alfabético, pues siempre en orden alfabético, pero por otro lado también puedes ordenarlas según su grupo principal de aplicación (formato, caja, etc.). Esto te ayudará cuando vuelvas sobre tu código tiempo después para buscar que hace exactamente tu regla.
  • Elige un solo idioma para el nombre de tus selectores. Es decir, ver en la misma hoja de estilos “navigation” y “navegacion” no es recomendable.
  • Agrupa clases en la medida en que puedas, esto te llevará a tener menos código y más legible.
  • Si lo crees oportuno, antes de publicar en producción comprime tu código. Por ejemplo en http://www.csscompressor.com/
  • Primero se diseña la estructura en HTML y después se ornamenta en CSS, no al revés.
  • Usa propiedades agrupadas (shorthands) cuando puedas. Es decir, mejor “margin: 5px” que no “margin-right: 5px;”, “margin-left: 5px”, etc. Por cierto, la regla nemotécnica para estas propiedades son el sentido de las agujas del reloj. Es decir arriba (top), derecha (right), abajo (bottom) e izquierda (left). Por curiosidad, decirte que hay otra regla nemotécnica que es la palabra TRouBLe (problema).
  • Definir un background-color y no asumir que será blanco, el usuario podría haberlo modificado y dar al traste con tu diseño.
  • Comenta tu código. Recuerda que tiempo después volverás sobre él y quizás ni tú mismo sepas que significa ese extraño código “indescifrable”.
  • Estructura tu hoja de estilos en secciones. Por ejemplo /*cabecera*/, /*cuerpo*/, /*pie*/, etc. Así después será más sencillo ubicarte en tu código.
  • Cuando estés trabajando con las pseudo-clases de los enlaces, ten en cuenta la siguiente regla nemotécnica “LoVe/HAte” (amor/odio). Esto es que el orden correcto es “link, visited, hover, active”, cualquier otro orden te dará problemas.
  • No pongas comillas en las rutas de imágenes css (parece ser que IE5/Mac se lleva mal con esto).
  • Evita el uso de !important;
  • Evita en la medida de lo posible el uso del posicionamiento absoluto.
  • El punto y coma ; final para la última propiedad de la regla, no es necesario. Pero yo, personalmente, me gusta ponerla porque si mañana amplias las propiedades no tienes que recordar escribir de nuevo el punto y coma.
  • Si quieres centrar elementos, ya sabes que margin: 0 auto; es la solución. De todas formas hay otras muchas maneras de lograr centrar un elemento http://ksesocss.blogspot.com/2012/05/centrando-al-centro-con-css-16-maneras.html
  • Si utilizas posicionamiento flotante, por favor, acuérdate de limpiar los floats (clear).
  • Intenta utilizar las etiquetas HTML para lo que fueron diseñadas originalmente. Es decir, <strong> no es negrita sino resaltado, <em> no es cursiva sino énfasis, etc.
  • No te hagas tus propios encabezados (<p style=”font-size: 18px;”></p>). Lo que tienes que hacer es utilizar los encabezados de HTML (h1, h2, …).
  • No des saltos entre encabezados HTML. Es decir, si en mi página hay un h3, tiene que haber también un h2 y un h1.
  • No utilices <br /> para crear espacios en blanco en el documento. Para eso está el margin-top o margin-bottom.
  • Formatea tu código CSS siempre con el mismo estilo. Es decir, espacios entre propiedades, entre las llaves de apertura y cierre de la regla… la verdad es que para eso Ctrl+K, Ctrl+D en Visual Studio facilita mucho la vida.

Muchas de estas recomendaciones han sido “reclutadas” a partir de los siguientes enlaces:

http://www.pixelovers.com/css-consejos-buenas-practicas-11635

http://www.polargeek.net/20-buenas-practicas-en-css/

http://www.torresburriel.com/weblog/2005/02/02/buenas-practicas-trabajando-con-css-traduccion-de-css-crib-sheet-de-dave-shea/

http://www.webdesignerdepot.com/2009/05/10-best-css-practices-to-improve-your-code/

http://www.davidvalverde.com/blog/50-buenas-practicas-en-css/

http://richardkmiller.com/209/css-best-practices

http://www.mezzoblue.com/archives/2003/11/17/css_best_pra/

http://www.graphicrating.com/2008/11/15/css-best-practices/ (*)

http://www.dezinerfolio.com/2009/02/20/css-standards-best-practices

http://www.thatwebguyblog.com/post/a_few_good_practices_for_optimising_your_css

http://pldleague.com/best-practices/do-i-write-good-css-code/

http://es.scribd.com/doc/89992/70-Expert-Ideas-For-Better-CSS

http://www.nebaris.com/post/69/como_ordenar_los_archivos_css

Un saludo!

viernes, 15 de abril de 2011

No sólo arrastrar y soltar controles de Telerik

Llevo mucho tiempo trabajando con los controles de Telerik de ASP.NET AJAX. En mi opinión son magníficos (que no me oiga mi compañero Dani que me dirá que luego son un llorica), y debo decir que aceleran el desarrollo de aplicaciones en gran medida. En cualquier caso, los mayores problemas que siempre encuentro cuando trabajo con ellos son los siguientes:

·         Exceso de recursos embebidos de tipo .js.

·         Exceso de recursos embebidos de tipo .css.

·         Difícil personalización de estilos css.

Intentando resumen lo anterior en una sola frase diría algo como “cada vez que agrego un control de Telerik, sé que estoy penalizando en parte el rendimiento de mi página porque conlleva X peticiones extras para ficheros .js y .css, y además como tenga que modificar su apariencia estoy bastante jodido y sólo podré hacerlo a base de ensayo-error y con la ayuda de !important”.

Por ejemplo, para una página sencilla donde simplemente queremos obtener un listado (que pagine y puede ser ordenado) de la tabla Northwind.Categories, tenemos que incluir el siguiente código (el control ScriptManager y SqlDataSource se ponen pero lógicamente no forman parte de este ejemplo).

        <asp:ScriptManager ID="ScriptManager1" runat="server">

        </asp:ScriptManager>

        <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"

            SelectCommand="SELECT [CategoryID], [CategoryName], [Description] FROM [Categories]">

        </asp:SqlDataSource>

        <telerik:RadGrid ID="RadGrid1" runat="server" AllowPaging="True" AllowSorting="True"

            DataSourceID="SqlDataSource1" GridLines="None" PageSize="5">

            <MasterTableView AutoGenerateColumns="False" DataKeyNames="CategoryID" DataSourceID="SqlDataSource1">

                <RowIndicatorColumn>

                    <HeaderStyle Width="20px"></HeaderStyle>

                </RowIndicatorColumn>

                <ExpandCollapseColumn>

                    <HeaderStyle Width="20px"></HeaderStyle>

                </ExpandCollapseColumn>

                <Columns>

                    <telerik:GridBoundColumn DataField="CategoryID" DataType="System.Int32" HeaderText="CategoryID"

                        ReadOnly="True" SortExpression="CategoryID" UniqueName="CategoryID">

                    </telerik:GridBoundColumn>

                    <telerik:GridBoundColumn DataField="CategoryName" HeaderText="CategoryName" SortExpression="CategoryName"

                        UniqueName="CategoryName">

                    </telerik:GridBoundColumn>

                    <telerik:GridBoundColumn DataField="Description" HeaderText="Description" SortExpression="Description"

                        UniqueName="Description">

                    </telerik:GridBoundColumn>

                </Columns>

            </MasterTableView>

        </telerik:RadGrid>

 

Veamos el tamaño y el número de peticiones que son necesarias para que la página funcione correctamente.

clip_image002

El resumen es:

·         16 peticiones

·         249 KB

Está claro que al ejecutar el sitio web en modo depuración, algunos recursos embebidos del tipo están sirviendo su versión de depuración (en vez de su versión release que está optimizada). De hecho, ejecutando la página en modo lanzamiento, obtenemos las siguientes estadísticas:

·         16 peticiones

·         282 KB

Como vemos, tampoco es muy definitiva la diferencia entre la versión debug y release del sitio web, pero en cualquier caso nuestro modo activo será release para ajustarnos más a la realidad de una aplicación web publicada en producción.

La primera conclusión es que a cualquiera le parecen excesivas 16 peticiones y un tamaño de casi 300 KB para servir una página .aspx que sólo incluye un listado de 5 registros. Queda claro que siguientes peticiones a la misma página ya servirían todos los recursos embebidos desde la caché local (por ejemplo, paginar a la segunda página recupera todo las peticiones desde la caché local, excepto el PostBack del formulario), pero aún así, vamos a ser quisquillosos y vamos a intentar mejorar esa primera petición.

Como primera medida para intentar optimizar la página, vamos a combinar la solicitud de ficheros .js a través de la etiqueta CompositeScript del control ScriptManager. El cómo llego aquí y cómo entender mejor esto se puede hacer visitando este blog y el excelente artículo que hay al respecto. En este blog nos invitan a usar el control ScriptReferenceProfiler, que puede ser descargado desde aquí. Veamos qué información nos muestra.

clip_image004

Nos informa que hay 8 peticiones a ficheros .js que podrían ser combinadas, así que el código de nuestro control ScriptManager pasa a ser el siguiente:

        <asp:ScriptManager ID="ScriptManager1" runat="server">

            <CompositeScript>

                <Scripts>

                    <asp:ScriptReference Name="MicrosoftAjax.js" />

                    <asp:ScriptReference Name="MicrosoftAjaxWebForms.js" />

                    <asp:ScriptReference Name="Telerik.Web.UI.Common.Core.js" Assembly="Telerik.Web.UI" />

                    <asp:ScriptReference Name="Telerik.Web.UI.Grid.RadGridScripts.js" Assembly="Telerik.Web.UI" />

                    <asp:ScriptReference Name="Telerik.Web.UI.Common.jQuery.js" Assembly="Telerik.Web.UI" />

                    <asp:ScriptReference Name="Telerik.Web.UI.Common.jQueryPlugins.js" Assembly="Telerik.Web.UI" />

                    <asp:ScriptReference Name="Telerik.Web.UI.Common.Navigation.NavigationScripts.js"

                        Assembly="Telerik.Web.UI" />

                    <asp:ScriptReference Name="Telerik.Web.UI.ComboBox.RadComboBoxScripts.js" Assembly="Telerik.Web.UI" />

                </Scripts>

            </CompositeScript>

        </asp:ScriptManager>

 

Y el resultado es que hemos bajado de 16 peticiones a 9 (con el ahorro de tráfico de red en round-trips que ello conlleva).

clip_image006

Aún así, 9 peticiones siguen siendo muchas peticiones. De estas 9 peticiones, tenemos lo siguiente:

·         La propia página, intocable.

·         Un super-fichero .js que es la combinación de todos los ficheros especificados, intocable.

·         2 Sprites con imágenes para la rejilla.

·         5 ficheros .css con estilos para la rejilla.

La primera duda que quiero solucionar es cómo saber qué ficheros .js son necesarios cada vez que se incluye un control del tipo RadGrid (imagina que si hubiéramos incluido en la página más controles de Telerik, no sabríamos decir – ni tampoco el ScriptReferenceProfiler – que ficheros .js ha solicitado cada control de la página). Para obtener la información de que ficheros .js carga cada control de Telerik, podemos visitar el siguiente enlace Disabling Embedded Resources.

A propósito de la lectura del enlace anterior de Telerik, podemos leer que la propiedad EnableEmbeddedScripts permite habilitar o deshabilitar (por defecto está habilitada) la carga de todos los ficheros .js que ha solicitado el control. La pregunta ahora es ¿Son necesarios estos ficheros .js? Pues bien, me puedo equivocar, pero creo que la respuesta es que son necesarios sólo si utilizamos características del control que necesitan del código existente en esos ficheros para funcionar. Por ejemplo, si establecemos la propiedad a False para el control RadGrid, podemos observar que la rejilla sigue paginando, ordenando, etc. Sin embargo, seleccionar una fila desde el cliente no funciona puesto que el control no dispone del código necesario ya que no se han incluido los ficheros .js necesarios para llevar a cabo esta acción. Además, tampoco funciona desplegar el combo para seleccionar el nº de filas por página, etc.

 

De este modo, es muy importante no arrastrar y soltar simplemente un control en nuestra página .aspx y esperar que haga todo el trabajo por nosotros. Debemos investigar que características queremos activar de ese control, y así y con una configuración personalizada, podemos optimizar el tamaño y velocidad de carga de nuestra página.

 

Lógicamente, cuando hablamos de una suite de controles como la de Telerik, esto puede ser una tarea ardua y llevarnos un tiempo precioso, pero los resultados hablan por sí mismos.

 

El siguiente enlace puede ser de mucha utilidad. Optimizing output, page load time and the overall performance of RadControls for ASP.NET AJAX.

 

 

La personalización de un control como el RadGrid no se queda aquí y hay decenas de propiedades que podemos tocar para personalizar la salida del control. Este post no pretende ser un post sobre el control RadGrid, así que no veremos estas propiedades pero espero que el ejemplo anterior haya levantado tu curiosidad sobre cómo parametrizar un control.

Por otro lado, aún tenemos pendiente 7 peticiones que fueran realizadas para cargar el estilo del RadGrid. A este respecto lo primero que hay que decir es que, normalmente, no te servirá ninguna de las skins predeterminadas que te ofrece Telerik. Lo cierto es que se agradece el intento. Pero después de un tiempo con ellas te das cuenta de que limitan tu creatividad y los diseños web que las acompañan (recordemos que normalmente una aplicación web no es solo una rejilla perdida en la inmesidad de una página).

Para agilizar la carga de estilos de Telerik, tenemos el control RadStyleSheetManager, que lo que hace es combinar todos los recursos embebidos relativos a estilos de la página (css, imágenes, etc.) para realizar un número menor de peticiones. La verdad es que este control es muy bueno y hace su función, pero nosotros lo que queremos es dar nuestro propio estilo a los controles de Telerik. En cualquier caso, este control es buenísimo para combinar nuestras propias hojas de estilo (siempre que estén expuestas como recursos embebidos de un ensamblado) en una sola petición. En cualquier caso, si incluimos el control RadStyleSheetManager, ahora nuestro flujo de peticiones vuelve a mejorar (5 peticiones de css pasan a ser sólo 1 petición combinada). El resto de peticiones siguen siendo la propia página, el script combinado y los sprites.

clip_image008

Las opciones más relevantes a la hora de personalizar la apariencia de los controles de Telerik son (además de seleccionar una de las skin predeterminadas que trae la suite y que la sirva automáticamente):

·         Registrar una skin predeterminada a mano.

·         Crear un skin personalizada.

·         No utilizar ninguna skin.

Para una lectura más detallada sobre este tema puedes visitar el enlace How skins work.

Registrar una skin predeterminada a mano es una opción pero no lo veo.  Vamos a centrarnos en crear una skin personalizada o en, directamente, no utilizar ninguna skin.

Para no utilizar ninguna skin, simplemente tenemos que establecer la propiedad Skin a “”. Esto se traduce en lo siguiente:

clip_image010

Como podemos observar, ya “casi” no tiene estilo pero aún así hay imágenes que aparecen. De este modo (me hubiera gustado que no fuera así) hay que ir a las propiedades que controlan que aparezcan esas imágenes y cambiar su valor. Por ejemplo:

<PagerStyle FirstPageImageUrl="" PrevPageImageUrl="" NextPageImageUrl="" LastPageImageUrl="" />

 

De todas formas ¿Cuantas imágenes de este tipo nos vamos a encontrar? Uff, la verdad es que no parece una solución definitiva lo de “no utilizar ninguna skin”. Lo cierto es que hay controles que no me han dado nada de guerra de este modo, por ejemplo RadMenu o RadToolTip, pero el RadGrid parece que está un poco más difícil.

Crear una skin personalizada es otra opción válida. Puedes ver cómo realizar el proceso en Creating a custom skin. Las distintas opciones pasan por crearla desde cero (un gran curro, créeme), tomar una skin base y modificarla (gran curro pero menos que desde cero) y por último utilizar una herramienta on-line que proporciona Telerik y que simplifica en gran parte el proceso. La herramienta es Telerik Visual Style Builder. Además, ahora es posible cargar estas skins personalizas como recursos embebidos en un ensamblado. How to load skins from external assemblies.

En cualquiera de los casos, sería fantástico tener una referencia de las clases css que utiliza cada control de Telerik (igual que antes encontramos que ficheros .js utilizaba cada control). Para encontrar esta información es necesario navegar en la ayuda de Telerik hasta el control deseado y allí podremos encontrar tanto el HTML generado por el control como el CSS utilizado para su estilo. Por ejemplo, para el RadGrid podemos ver su HTML aquí y su CSS aquí.

En cualquier caso, también he de decirte que la ayuda de Telerik no está todo lo actualizada que debiera, así que al final tendrás que tirar de Firebug para saber exactamente que HTML y que estilos se están aplicando.

Para un siguiente post (y porque un proyecto en el que estoy inmerso ahora mismo lo requiere) veremos cómo crear una skin personalizada y servirla como un recurso embebido en un ensamblado.

Un saludo!