<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Juanma Santoyo</title>
	<atom:link href="http://www.juanmasantoyo.es/index.php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.juanmasantoyo.es</link>
	<description>En ocasiones me llaman friki</description>
	<lastBuildDate>Wed, 07 Jul 2010 04:57:03 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Animar transformaciones en WPF con el método BeginAnimation.</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/07/06/animar-transformaciones-en-wpf-con-el-metodo-beginanimation/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/07/06/animar-transformaciones-en-wpf-con-el-metodo-beginanimation/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 22:17:31 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[surface]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=475</guid>
		<description><![CDATA[Me preguntaron hace poco cómo animar elementos en Microsoft Surface. En esencia se haría como en cualquier entorno basado en WPF.
Hay varias formas de animar, pero quizás una de las más sencilla y potente sea la animación de transformaciones con el método BeginAnimation.

Las transformaciones.
En WPF existen varios tipos de transformaciones:

RotateTransform. Cambia la orientación de un [...]]]></description>
			<content:encoded><![CDATA[<p>Me preguntaron hace poco cómo animar elementos en Microsoft Surface. En esencia se haría como en cualquier entorno basado en WPF.</p>
<p>Hay varias formas de animar, pero quizás una de las más sencilla y potente sea la animación de transformaciones con el método <em>BeginAnimation</em>.<br />
<span id="more-475"></span></p>
<h3>Las transformaciones.</h3>
<p>En WPF existen varios tipos de transformaciones:</p>
<ul>
<li><em><a href="http://msdn.microsoft.com/es-es/library/system.windows.media.rotatetransform.aspx">RotateTransform</a></em>. Cambia la orientación de un elemento.</li>
<li><em><a href="http://msdn.microsoft.com/es-es/library/system.windows.media.scaletransform.aspx">ScaleTransform</a></em>. Cambia el tamaño de un elemento.</li>
<li><em><a href="http://msdn.microsoft.com/es-es/library/system.windows.media.translatetransform.aspx">TranslateTransform</a></em>. Cambia la posición de un elemento.</li>
<li><em><a href="http://msdn.microsoft.com/es-es/library/system.windows.media.transformgroup.aspx">TransformGroup</a></em>. Es un tipo de transformación especial, ya que consiste en una combinación de las tres anteriores.</li>
</ul>
<h3>Animar transformaciones.</h3>
<p>La idea es simple: Una animación consiste en modificar progresivamente el valor de una propiedad durante un periodo de tiempo. En principio, se puede animar cualquier propiedad de dependencia del API de WPF.</p>
<p>Concretamente, las transformaciones usan propiedades de dependencia para modificar el aspecto del elemento en el que se aplican; así que si aplicamos una animación sobre una propiedad de una transformación de cualquier tipo, el resultado será una animación sobre el elemento.</p>
<p>El código para aplicar una transformación es sencillo. Se puede aplicar desde XAML o desde C#, pero en lo personal prefiero hacerlo en XAML:</p>
<pre class="brush:xml">	&lt;Image x:Name="MyImage" Source="images/myimage.png" Width="100" Height="100"&gt;
		&lt;Image.RenderTransform&gt;
			&lt;TransformGroup&gt;
				&lt;TranslateTransform x:Name="Translacion" X="85" /&gt;
				&lt;RotateTransform x:Name="Rotacion" Angle="0" CenterX="15" CenterY="15" /&gt;
			&lt;/TransformGroup&gt;
		&lt;/Image.RenderTransform&gt;
	&lt;/Image&gt;
</pre>
<p>Fijaos que al usar el nodo <em>&#8220;TransformGroup&#8221;</em> podemos aplicar más de una transformación. De no usarlo sólo podríamos aplicar una, ya que el nodo <em>&#8220;Image.RenderTransform&#8221;</em> sólo admite un nodo hijo. Notad también que las transformaciones se aplican desde la última a la primera. No es lo mismo mover y rotar, que rotar y mover.</p>
<h3>Las animaciones y el método BeginAnimation.</h3>
<p>A nivel práctico, una animación es un objeto con una serie de propiedades configuradas, como por ejemplo la duración de la animación, la aceleración, el valor inicial y final de la propiedad, etc. Dependiendo del tipo de dato que queramos animar, el objeto de animación cambia. No es lo mismo animar un color (<em>ColorAnimation</em>) que una orientación (<em>DoubleAnimation</em>). Se pueden ver todos los tipos de animación posible en la especificación de la clase madre: <em><a href="http://msdn.microsoft.com/es-es/library/system.windows.media.animation.animationtimeline.aspx">AnimationTimeLine</a></em>.</p>
<p>Para aplicar una animación sobre una transformación, contamos con un potente aliado: el método <em>BeginAnimation</em>, presente en todas las transformaciones. Al método <em>BeginAnimation</em> se le pasan dos parámetros: la propiedad de dependencia a animar, y la animación. La animación deberemos construirla en base a lo que queremos animar, la propiedad de dependencia es una propiedad estática de la clase a la que pertenece el elemento que queremos animar. Por ejemplo, si queremos animar el ángulo de un <em>RotateTransform</em>, tendremos una propiedad estática &#8220;<em>RotateTransform.AngleProperty</em>&#8220;. Más fácil con un poco de código C#:</p>
<pre class="brush:csharp">
	DoubleAnimation animacion = new DoubleAnimation();

	animacion.To = 180;
	animacion.Duration = new Duration(TimeSpan.FromMilliseconds(1000));

	Rotacion.BeginAnimation(RotateTransform.AngleProperty, animacion);
</pre>
<h3>Es todo por el momento.</h3>
<p>Y en realidad no hay mucho más que decir sobre animaciones. Sólo destacar que, como imagináis, el objeto animación tiene eventos que informarán del estado del proceso, y que no son bloqueantes (es decir, mientras una animación se ejecuta, el flujo del programa no se detiene, por lo que necesitan una gestión asíncrona). También destacar que la animación se iniciará en el instante en que se ejecute el método <em>BeginAnimation</em>.</p>
<p>Si queréis aprender sobre animaciones más complejas, os recomiendo que miréis el objeto <em><a href="http://msdn.microsoft.com/en-us/library/system.windows.media.animation.storyboard.aspx">StoryBoard</a></em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/07/06/animar-transformaciones-en-wpf-con-el-metodo-beginanimation/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Vídeo de Rent a Car Surface by Bizzit</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/07/06/video-de-rent-a-car-surface-by-bizzit/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/07/06/video-de-rent-a-car-surface-by-bizzit/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 21:28:47 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[software]]></category>
		<category><![CDATA[surface]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=463</guid>
		<description><![CDATA[Ya he hablado en mi blog algúna vez sobre la demo para Microsoft Surface que estábamos realizando en Bizzit.
La aplicación fue principalmente desarrollada por un servidor (me refiero al que escribe, no a un servidor de aplicaciones  ), y fue un reto muy bonito. La verdad es que ha sido una experiencia profesional muy [...]]]></description>
			<content:encoded><![CDATA[<p>Ya he hablado en mi blog algúna vez sobre la demo para Microsoft Surface que estábamos realizando en Bizzit.</p>
<p>La aplicación fue principalmente desarrollada por un servidor (me refiero al que escribe, no a un servidor de aplicaciones <img src='http://www.juanmasantoyo.es/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> ), y fue un reto muy bonito. La verdad es que ha sido una experiencia profesional muy interesante y divertida.</p>
<p>Bueno, al tema: Mi compañero en esta aventura, Carlos García; ha realizado un vídeo donde se puede ver cómo es la aplicación y su funcionamiento. Me llena de orgullo y satisfacción compartirlo con todos vosotros:</p>
<div style="text-align: center;"><object width="425" height="355" type="application/x-shockwave-flash" data="http://www.youtube.com/v/ax-0BToUTGo"><param name="movie" value="http://www.youtube.com/v/ax-0BToUTGo" />Este video fue agregado usando YouTuber, plugin desarrollado por <a href="http://www.roytanck.com">Roy Tanck</a>. Se requiere Adobe Flash Player para visualizarlo.</object></div>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/07/06/video-de-rent-a-car-surface-by-bizzit/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ocultar el texto de un input submit</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/06/11/ocultar-el-texto-de-un-input-submit/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/06/11/ocultar-el-texto-de-un-input-submit/#comments</comments>
		<pubDate>Fri, 11 Jun 2010 05:17:35 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[css]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=459</guid>
		<description><![CDATA[Ayer me surgió la necesidad de ocultar el texto de un Input Submit con CSS.
¿Es una locura?. No, porque mi botón tenía una imagen de fondo lo suficientemente descriptiva como para no tener texto.

Una opción podría ser dejar el atributo value vacío, pero necesitaba el value para poder discriminar después en el servidor (tenía más [...]]]></description>
			<content:encoded><![CDATA[<p>Ayer me surgió la necesidad de ocultar el texto de un Input Submit con CSS.</p>
<p>¿Es una locura?. No, porque mi botón tenía una imagen de fondo lo suficientemente descriptiva como para no tener texto.<br />
<span id="more-459"></span><br />
Una opción podría ser dejar el atributo value vacío, pero necesitaba el value para poder discriminar después en el servidor (tenía más de un botón, y necesitaba saber cual se había pulsado). Además, siendo estrictos, el value no debería ser la solución a un problema gráfico.</p>
<p>En definitiva, la solución que encontré en <a href="http://www.altrugon.com/es/css/hide-text-from-submit-button-with-cssocultar-texto-del-boton-submit-con-css/">esta entrada</a> y que posteriormente apliqué consiste en este código CSS:</p>
<pre class="brush:css">
	input.hidden_text
	{
		/* Imagen de fondo */
		background: transparent url(“imagen.jpg”) left center no-repeat;   

		/* Tamaño de la imagen */
		width: 20px;
		height: 20px;

		text-indent: -9999px;
		border: none;
		color: transparent;

		/* Parche para IE  */
		text-transform: capitalize;
	}
</pre>
<p>Espero que os resulte útil.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/06/11/ocultar-el-texto-de-un-input-submit/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Charla sobre Microsoft Surface</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/05/28/charla-sobre-microsoft-surface/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/05/28/charla-sobre-microsoft-surface/#comments</comments>
		<pubDate>Fri, 28 May 2010 15:15:12 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[surface]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=455</guid>
		<description><![CDATA[Ayer dí una charla sobre Microsoft Surface en el centro de Innovación de Microsoft de Palma para el grupo de desarrolladores de .Net en Baleares.
Hablamos un poco de todo lo que implica la Surface y el desarrollo de aplicaciones para este dispositivo. Fue una experiencia muy gratificante.
Dejo la descarga del Power Point que redacté para [...]]]></description>
			<content:encoded><![CDATA[<p>Ayer dí una charla sobre Microsoft Surface en el centro de Innovación de Microsoft de Palma para el grupo de desarrolladores de .Net en Baleares.</p>
<p>Hablamos un poco de todo lo que implica la Surface y el desarrollo de aplicaciones para este dispositivo. Fue una experiencia muy gratificante.</p>
<p>Dejo la descarga del Power Point que redacté para la ocasión, por si os interesa.</p>
<p><a href='http://www.juanmasantoyo.es/wp-content/uploads/2010/05/Microsoft-Surface.zip'>Microsoft Surface</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/05/28/charla-sobre-microsoft-surface/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>ScatterViewItem invisibles en Microsoft Surface</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/05/18/scatterviewitem-invisibles-en-microsoft-surface/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/05/18/scatterviewitem-invisibles-en-microsoft-surface/#comments</comments>
		<pubDate>Tue, 18 May 2010 06:00:57 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[surface]]></category>
		<category><![CDATA[scatterviewitem invisible]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=449</guid>
		<description><![CDATA[Cuando empecé a desarrollar para Microsoft Surface, me di cuenta de tres cosas:

El control ScatterViewItem es la base de toda aplicación.
La mayoría de las veces, no queremos que el ScatterViewItem tenga la apariencia tan horrible que tiene por defecto, es más, nos interesará que sea &#8220;invisible&#8221;.
El control ScatterViewItem no proporciona ningun sistema simple para volverse [...]]]></description>
			<content:encoded><![CDATA[<p>Cuando empecé a desarrollar para Microsoft Surface, me di cuenta de tres cosas:</p>
<ol>
<li>El control ScatterViewItem es la base de toda aplicación.</li>
<li>La mayoría de las veces, no queremos que el ScatterViewItem tenga la apariencia tan horrible que tiene por defecto, es más, nos interesará que sea &#8220;invisible&#8221;.</li>
<li>El control ScatterViewItem no proporciona ningun sistema simple para volverse invisible.</li>
</ol>
<p>Así que despues de trastear un poco con Microsoft Expression Blend, conseguí montar un pequeño estilo que podemos aplicar a nuestros ScatterViewItem para que estos sean invisibles. Esto es, inapreciables para el usuario. Por lo tanto, el contenido se verá perfectamente, pero las sombras, reflejos, destellos y demás tonterías, no.<br />
<span id="more-449"></span><br />
Este es el estilo en cuestión:</p>
<pre class="brush:xml">
&lt;Style x:Key=&quot;InvisibleScatterViewItem&quot; TargetType=&quot;{x:Type s:ScatterViewItem}&quot;&gt;
    &lt;Setter Property=&quot;Template&quot;&gt;
        &lt;Setter.Value&gt;
            &lt;ControlTemplate TargetType=&quot;{x:Type s:ScatterViewItem}&quot;&gt;
                &lt;ContentPresenter /&gt;
            &lt;/ControlTemplate&gt;
        &lt;/Setter.Value&gt;
    &lt;/Setter&gt;
&lt;/Style&gt;
</pre>
<p>Espero que os sirva tanto como a mí.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/05/18/scatterviewitem-invisibles-en-microsoft-surface/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Introducción al componente ScatterView de Surface (1: ScatterViews con XAML)</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/04/08/introduccion-al-componente-scatterview-de-surface-parte-1/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/04/08/introduccion-al-componente-scatterview-de-surface-parte-1/#comments</comments>
		<pubDate>Thu, 08 Apr 2010 12:30:16 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[surface]]></category>
		<category><![CDATA[scatterview]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=332</guid>
		<description><![CDATA[El multitouch es probablemente una de las características más atractivas de Surface. Esto se debe a que plantea una serie de posibilidades al usuario que convierte su experiencia en algo mucho más intuitivo y sencillo.
El componente ScatterView es quizás uno de los mejores ejemplos de esto. Este es el primero de varios artículos en el [...]]]></description>
			<content:encoded><![CDATA[<p>El multitouch es probablemente una de las características más atractivas de Surface. Esto se debe a que plantea una serie de posibilidades al usuario que convierte su experiencia en algo mucho más intuitivo y sencillo.</p>
<p>El componente <em>ScatterView</em> es quizás uno de los mejores ejemplos de esto. Este es el primero de varios artículos en el que veremos cómo se usan y qué posiblides nos ofrecen.<br />
<span id="more-332"></span></p>
<h3>Sobre el componente <em>ScatterView</em></h3>
<p>Un <em>ScatterView</em> representa un elemento que reacciona a los contactos sobre Surface y que se puede mover, rotar o redimensionar.</p>
<p>El ejemplo más clásico sería un puñado de fotografías. Cada una de esas fotografías puede ser un <em>ScatterView</em>.</p>
<h3>Preparamos el proyecto</h3>
<p>Antes de iniciar el Visual Studio, debemos haber iniciado el emulador de Surface que viene con el SDK. Si no lo has hecho así, cierra el Visual Studio y inícialo todo en el orden correcto.</p>
<h4>Creamos el proyecto</h4>
<p>Nuestro proyecto va a ser una aplicación para Surface basada en WPF. Lo llamaremos HelloScatterView.</p>
<p>Al crear nuestro proyecto se nos ha creado una ventana por defecto: SurfaceWindow1. La renombraremos, y le pondremos el nombre de &#8220;<strong>XamlSample</strong>&#8220;.</p>
<h4>Añadimos unas imágenes</h4>
<p>Para poder trabajar con los <strong>ScatterViews</strong>, necesitaremos algunas imágenes.</p>
<p>Dentro de nuestro proyecto Surface tenemos una carpeta llamada Resources. Crearemos otra carpeta en su interior llamada Img y ubicaremos ahí nuestras imágenes.</p>
<h3>Añadir <em>ScatterViews</em> desde XAML</h3>
<h4><em>ScatterView</em> simple con XAML</h4>
<p>Comenzaremos usando los <em>ScatterViews</em> desde XAML. En realidad añadir un <em>ScatterView</em> es muy simple:</p>
<pre class="brush:xml">
&lt;s:ScatterView&gt;
    &lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
&lt;/s:ScatterView&gt;
</pre>
<p><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/01-300x225.jpg" alt="" title="Ejemplo de ScatterView" width="300" height="225" class="aligncenter size-medium wp-image-333" /></p>
<p>Este es el código que añade un <em>ScatterView</em>. Fijaos en un detalle: añadir un <em>ScatterView</em> no es sólo añadir el nodo <em>ScatterView</em>, también es añadir el recurso que se manejará, en este caso la imagen. Y es que un <em>ScatterView</em> no es una imagen, sino la capacidad que tiene un elemento (en este caso una imagen) de ser rotado, redimensionado y movido.</p>
<p>El XAML completo de la ventana es este:</p>
<pre class="brush:xml">
&lt;s:SurfaceWindow
    x:Class=&quot;HelloScatterView.SurfaceWindow1&quot;
    xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
    xmlns:s=&quot;http://schemas.microsoft.com/surface/2008&quot;
    Title=&quot;HelloScatterView&quot;&gt;
    &lt;s:SurfaceWindow.Resources&gt;
        &lt;ImageBrush x:Key=&quot;WindowBackground&quot;
                  Stretch=&quot;None&quot; Opacity=&quot;0.6&quot;
                  ImageSource=&quot;pack://application:,,,/Resources/WindowBackground.jpg&quot;/&gt;
    &lt;/s:SurfaceWindow.Resources&gt;
    &lt;s:ScatterView&gt;
        &lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
    &lt;/s:ScatterView&gt;
&lt;/s:SurfaceWindow&gt;
</pre>
<p>Si ahora compilamos nuestro proyecto, podremos jugar un poco con nuestra foto sobre el emulador de Surface. Incluso, si conectas dos ratones por USB puedes simular multitouch.</p>
<p>Vamos a hacerlo un poco más espectacular añadiendo varias imágenes:</p>
<pre class="brush:xml">
&lt;s:ScatterView&gt;
    &lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
    &lt;Image Source=&quot;Resources/Img/kiyoumizu_dera.jpg&quot;/&gt;
    &lt;Image Source=&quot;Resources/Img/laputa_robot.jpg&quot;/&gt;
    &lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
    &lt;Image Source=&quot;Resources/Img/kiyoumizu_dera.jpg&quot;/&gt;
    &lt;Image Source=&quot;Resources/Img/laputa_robot.jpg&quot;/&gt;
&lt;/s:ScatterView&gt;
</pre>
<p><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/02-300x225.jpg" alt="" title="Ejemplo de varios ScatterViews" width="300" height="225" class="aligncenter size-medium wp-image-334" /></p>
<h4><em>Scatterviews</em> complejos con XAML</h4>
<p>Probablemente ya te estés preguntando lo siguiente: ¿cómo determinar los parámetros por defecto de nuestro <em>ScatterView</em>? Vamos a ello.</p>
<p>La clave está en que la estructura que hemos usado ahora no acaba de ser la mejor. En realidad, nos está faltando crear un <em>ScatterViewItem</em>, que hasta el momento se estaba creando de forma automática para cada elemento en el <em>ScatterView</em>.</p>
<pre class="brush:xml">
&lt;s:ScatterView&gt;
	&lt;s:ScatterViewItem&gt;
		&lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;
&lt;/s:ScatterView&gt;
</pre>
<p>En el nodo <em>ScatterViewItem</em> podemos establecer muchas propiedades que afectarán al comportamiento de nuestro <em>ScatterView</em>.</p>
<p>Algunas de esas propiedades son:</p>
<ul>
<li><strong>MinWidth</strong>, <strong>MaxWidth</strong>, <strong>MinHeight</strong>, <strong>MaxHeight</strong>: Máximos y mínimos de anchura y altura.</li>
<li><strong>CanMove</strong>, <strong>CanRotate</strong>, <strong>CanScale</strong>: Activan o desactivan las capacidades de mover, rotar y redimensionar.</li>
<li><strong>Width</strong>, <strong>Height</strong>, <strong>Center</strong>, <strong>Orientation</strong>: Valores iniciales para el ancho, el alto, la posición, y la rotación.</li>
<li><strong>BorderBrush</strong>, <strong>BorderThikness</strong>: Color y grosor del borde.</li>
</ul>
<p>Un ejemplo sencillo:</p>
<pre class="brush:xml">
&lt;s:ScatterView&gt;
	&lt;s:ScatterViewItem Center=&quot;512,384&quot; Orientation=&quot;0&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Center=&quot;512,384&quot; Orientation=&quot;60&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/kiyoumizu_dera.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Center=&quot;512,384&quot; Orientation=&quot;180&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/laputa_robot.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Center=&quot;512,384&quot; Orientation=&quot;240&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Center=&quot;512,384&quot; Orientation=&quot;300&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/kiyoumizu_dera.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Center=&quot;512,384&quot; Orientation=&quot;360&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/laputa_robot.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;
&lt;/s:ScatterView&gt;
</pre>
<p>Aunque de hecho, podemos centralizar la mayoría de estas propiedades en un único nodo, como un estilo:</p>
<pre class="brush:xml">
&lt;s:ScatterView&gt;
	&lt;s:ScatterView.ItemContainerStyle&gt;
		&lt;Style TargetType=&quot;{x:Type s:ScatterViewItem}&quot;&gt;
			&lt;Setter Property=&quot;Center&quot; Value=&quot;512,384&quot;/&gt;
			&lt;Setter Property=&quot;BorderBrush&quot; Value=&quot;Black&quot;/&gt;
			&lt;Setter Property=&quot;BorderThickness&quot; Value=&quot;3&quot;/&gt;
		&lt;/Style&gt;
	&lt;/s:ScatterView.ItemContainerStyle&gt;

	&lt;s:ScatterViewItem Orientation=&quot;0&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Orientation=&quot;60&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/kiyoumizu_dera.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Orientation=&quot;180&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/laputa_robot.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Orientation=&quot;240&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/fuente_tres_chorros.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Orientation=&quot;300&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/kiyoumizu_dera.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;

	&lt;s:ScatterViewItem Orientation=&quot;360&quot;&gt;
		&lt;Image Source=&quot;Resources/Img/laputa_robot.jpg&quot;/&gt;
	&lt;/s:ScatterViewItem&gt;
&lt;/s:ScatterView&gt;
</pre>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/03.jpg"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/03-300x225.jpg" alt="" title="Definiendo las propiedades por defecto de los ScatterViews" width="300" height="225" class="aligncenter size-medium wp-image-335" /></a></p>
<h3>Es todo por hoy</h3>
<p>El componente <em>ScatterView</em> es sencillo de usar y proporciona una característica muy interesante a nuestras aplicaciones.</p>
<p>Cuando se trabaja para Surface, hay que tener muy en cuenta que los diversos usuarios se colocan alrededor de la mesa, por lo que no existe el derecho ni el revés. Los ScatterViews nos solucionarán este problema más de una vez.</p>
<p>En la siguiente parte del artículo, veremos cómo trabajar con ScatterViews desde C#.</p>
<h3>Editado 7/5/2010:</h3>
<p>Me comentaron que los códigos fuente en XAML tenían mal la sintaxis, y efectívamente; cuando he pasado a revisarlo así era. Ni idea de que pudo pasar&#8230; Bueno, ya están arreglados.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/04/08/introduccion-al-componente-scatterview-de-surface-parte-1/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Enrutamiento Seo Friendly con asp.Net</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/04/06/enrutamiento-seo-friendly-con-asp-net/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/04/06/enrutamiento-seo-friendly-con-asp-net/#comments</comments>
		<pubDate>Tue, 06 Apr 2010 21:55:48 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[enrutamiento seo]]></category>
		<category><![CDATA[friendly url]]></category>
		<category><![CDATA[seo friendly]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=423</guid>
		<description><![CDATA[En los últimos años se ha ido estableciendo en los sitios web una buena práctica: las Seo Friendly URL. Friendly de amistoso, por que hace que nuestras rutas sean fáciles de indexar por los buscadores (los parámetros GET nunca les han gustado demasiado) y, mucho más importante; fáciles de comprender por los usuarios.
Es de sentido [...]]]></description>
			<content:encoded><![CDATA[<p>En los últimos años se ha ido estableciendo en los sitios web una buena práctica: las <em>Seo Friendly URL</em>. Friendly de amistoso, por que hace que nuestras rutas sean fáciles de indexar por los buscadores (los parámetros <em>GET</em> nunca les han gustado demasiado) y, mucho más importante; fáciles de comprender por los usuarios.</p>
<p>Es de sentido común que la URL de una página tenga que tener cierta relación con lo que contiene. A nadie le dice nada una URL de tipo http://www.dominio.com?seccion=5, pero la cosa es más interesante si es algo del tipo http://www.dominio.com/contacto. La propia URL de este artículo es un buen ejemplo.</p>
<p>En este artículo veremos un pequeño ejemplo de como podemos crear Friendly URLs en <em>asp.Net</em><br />
<span id="more-423"></span></p>
<h3>¿En que consisten técnicamente las <em>Friendly URL</em>?</h3>
<p>La idea es interceptar las peticiones por URL que se realizan a nuestro sitio web antes de que se sirva ningún contenido, de forma que podamos analizar la ruta y servir un archivo u otro en consecuencia. También podemos considerar que parte de la URL es un parámetro de entrada.</p>
<p>Por ejemplo, la URL de este artículo podría ser una como <em>http://www.dominio.com/articulos/enrutamiento-friendly-url/</em>, donde la parte &#8220;enrutamiento-friendly-url&#8221; es la que determina qué artículo se está mostrando.</p>
<h3>¿Cómo montamos el nuevo sistema de direccionamiento?</h3>
<p>Cada tecnología de servidor tiene su forma de hacerlo. En este artículo veremos un ejemplo sobre <em>asp.Net</em>.</p>
<p>La clave es el archivo <em>Global.asax</em>. Este es un archivo que proporciona manejadores para una serie de eventos producidos por la aplicación. A nosotros nos interesará el evento <em>Application_BeginRequest</em>: es ahí donde podemos interceptar las peticiones antes de que se sirva ningún contenido, y donde analizaremos las URL para reprogramar el direccionamiento a donde nos interese. Obviamente, el archivo <em>Global.asax</em> tiene más utilidades que el enrutamiento, pero de momento no nos interesan.</p>
<h3>Un ejemplo</h3>
<p>Vamos a programar un pequeño ejemplo que nos serviría para gestionar los direccionamientos de una red social.</p>
<p>Haremos una dirección para las secciones principales, y una dirección que será dinámica para cada usuario miembro de la red social.</p>
<h4>Diseñamos el nuevo enrutamiento</h4>
<p>Como siempre, antes de empezar a hacer nada; necesitamos tener claro qué queremos hacer. Vamos a considerar todas las rutas que tendremos.</p>
<ol>
<li>
		<strong><em>/inicio/</em></strong><br />
		Todos los sitios web, las redes sociales también; necesitan una página de inicio.
	</li>
<li>
		<strong><em>/buscar/</em></strong><br />
		Toda red social necesita un buscador.
	</li>
<li>
		<strong><em>/usuarios/</em></strong><br />
		Lo más importante de una red social son los usuarios. Esta es la página genérica de usuarios, que podría ser por ejemplo un formulario de Login.
	</li>
<li>
		<strong><em>/usuarios/&lt;nombre de usuario&gt;/</em></strong><br />
		Todos los usuarios tienen un perfil con su nombre, su foto, las cosas que hacen los domingos&#8230; Fijaos en que ya incluímos un parámetro, el nombre del usuario.
	</li>
<li>
		<strong><em>/usuarios/&lt;nombre de usuario&gt;/contacto/</em></strong><br />
		La gracia de una red social es poder contactar con los usuarios. Esta página proporcionaría funcionalidad a una red de mensajería interna. Tambien tenemos el parámetro de nombre de usuario.
	</li>
</ol>
<h4>Creamos el proyecto</h4>
<p>Vamos a crear un proyecto web normal y corrente desde el <em>Visual Studio</em>.</p>
<p>Crearemos cuatro <em>.aspx</em>, uno para cada una de nuestras rutas, excepto para <em>/inicio/</em>, que será el <em>Default.aspx</em> que se ha creado por defecto. Tambien crearemos una clase <em>.cs</em> para simular el origen de datos de los usuarios.</p>
<ul>
<li><em>Buscar.aspx</em></li>
<li><em>Usuarios.aspx</em></li>
<li><em>UsuariosPerfil.aspx</em></li>
<li><em>UsuariosContacto.aspx</em></li>
<li><em>Datos/Usuarios.cs</em></li>
</ul>
<h4>Algo de código para los <em>.aspx</em></h4>
<p>Vamos a añadir algo de código en los <em>.aspx</em>. Para diferenciarlos, más que nada; y para probar unos links.</p>
<h5><em>Default.aspx</em></h5>
<pre class="brush:xml">
	&lt;head runat=&quot;server&quot;&gt;
		&lt;title&gt;Inicio&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;form id=&quot;form1&quot; runat=&quot;server&quot;&gt;
		&lt;div&gt;
			&lt;h1&gt;Inicio&lt;/h1&gt;

			&lt;ul&gt;
				&lt;li&gt;&lt;asp:LinkButton runat=&quot;server&quot; ID=&quot;lbBuscar&quot; PostBackUrl=&quot;~/buscar/&quot;&gt;Buscar&lt;/asp:LinkButton&gt;&lt;/li&gt;
				&lt;li&gt;&lt;asp:LinkButton runat=&quot;server&quot; ID=&quot;lbUsuarios&quot; PostBackUrl=&quot;~/usuarios/&quot;&gt;Usuarios&lt;/asp:LinkButton&gt;&lt;/li&gt;
			&lt;/ul&gt;
		&lt;/div&gt;
		&lt;/form&gt;
	&lt;/body&gt;
</pre>
<h5><em>Buscar.aspx</em></h5>
<pre class="brush:xml">
	&lt;head runat=&quot;server&quot;&gt;
		&lt;title&gt;Buscar&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;form id=&quot;form1&quot; runat=&quot;server&quot;&gt;
		&lt;div&gt;
			&lt;h1&gt;Buscar&lt;/h1&gt;

			&lt;ul&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbInicio&quot; runat=&quot;server&quot; PostBackUrl=&quot;~/inicio/&quot;&gt;Inicio&lt;/asp:LinkButton&gt;&lt;/li&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbUsuarios&quot; runat=&quot;server&quot; PostBackUrl=&quot;~/usuarios/&quot;&gt;Usuarios&lt;/asp:LinkButton&gt;&lt;/li&gt;
			&lt;/ul&gt;
		&lt;/div&gt;
		&lt;/form&gt;
	&lt;/body&gt;
</pre>
<h5><em>Usuarios.aspx</em></h5>
<pre class="brush:xml">
	&lt;head runat=&quot;server&quot;&gt;
		&lt;title&gt;Usuarios&lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;form id=&quot;form1&quot; runat=&quot;server&quot;&gt;
		&lt;div&gt;
			&lt;h1&gt;Usuarios&lt;/h1&gt;

			&lt;ul&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbInicio&quot; runat=&quot;server&quot; PostBackUrl=&quot;~/inicio/&quot;&gt;Inicio&lt;/asp:LinkButton&gt;&lt;/li&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbBuscar&quot; runat=&quot;server&quot; PostBackUrl=&quot;~/buscar/&quot;&gt;Buscar&lt;/asp:LinkButton&gt;&lt;/li&gt;
			&lt;/ul&gt;
		&lt;/div&gt;
		&lt;/form&gt;
	&lt;/body&gt;
</pre>
<h5><em>UsuariosPerfil.aspx</em></h5>
<pre class="brush:xml">
	&lt;head runat=&quot;server&quot;&gt;
		&lt;title&gt;Perfil de &lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;form id=&quot;form1&quot; runat=&quot;server&quot;&gt;
		&lt;div&gt;
			&lt;h1 runat=&quot;server&quot; id=&quot;hTitle&quot;&gt;&lt;/h1&gt;

			&lt;ul&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbInicio&quot; runat=&quot;server&quot; PostBackUrl=&quot;~/inicio/&quot;&gt;Inicio&lt;/asp:LinkButton&gt;&lt;/li&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbUsuariosContacto&quot; runat=&quot;server&quot;&gt;Perfíl de &lt;/asp:LinkButton&gt;&lt;/li&gt;
			&lt;/ul&gt;
		&lt;/div&gt;
		&lt;/form&gt;
	&lt;/body&gt;
</pre>
<h5><em>UsuariosContacto.aspx</em></h5>
<pre class="brush:xml">
	&lt;head runat=&quot;server&quot;&gt;
		&lt;title&gt;Contactar con &lt;/title&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;form id=&quot;form1&quot; runat=&quot;server&quot;&gt;
		&lt;div&gt;
			&lt;h1 runat=&quot;server&quot; id=&quot;hTitle&quot;&gt;Contactar con &lt;/h1&gt;

			&lt;ul&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbinicio&quot; runat=&quot;server&quot; PostBackUrl=&quot;~/inicio/&quot;&gt;Inicio&lt;/asp:LinkButton&gt;&lt;/li&gt;
				&lt;li&gt;&lt;asp:LinkButton ID=&quot;lbUsuariosPerfil&quot; runat=&quot;server&quot;&gt;Perfíl de &lt;%= getUserName() %&gt;&lt;/asp:LinkButton&gt;&lt;/li&gt;
			&lt;/ul&gt;
		&lt;/div&gt;
		&lt;/form&gt;
	&lt;/body&gt;
</pre>
<p>Debemos considerar, además, un poco de código en los <em>.cs</em>:</p>
<h5><em>Datos/Usuarios.cs</em></h5>
<p>Este será nuestro origen de datos. Normalmente será una tabla en base de datos, un xml, o algo por el estilo; pero para nuestro ejemplo nos basta una clase que extienda de List. Le hemos programado además dos nuevos métodos: uno para convertir un valor de la lista al formato que usamos en las URL, y otro para encontrar valores. Destacar que el algoritmo de búsqueda podría ser bastante mejor, pero para el caso ya nos sirve.</p>
<pre class="brush:csharp">
	using System;
	using System.Collections.Generic;

	namespace JuanmaSantoyoSeoFriendly.Datos
	{
		public class Usuarios : List&lt;string&gt;
		{
			public Usuarios()
			{
				this.Add("John Travolta");
				this.Add("Samuel L Jackson");
				this.Add("Bruce Willis");
				this.Add("Uma Thurman");
				this.Add("Quentin Tarantino");
			}
		}

		private string urlFormat(string str)
        {
            return str.ToLowerInvariant().Replace(&quot; &quot;, &quot;-&quot;);
        }

        public int search(string username)
        {
            int userid = -1;
            int i = 0;

            while(this.Count &gt; i)
            {
                if (urlFormat(this[i]) == username)
                {
                    userid = i;
                    break;
                }

                i  ;
            }

            return userid;
        }
	}
</pre>
<h5><em>UsuariosPerfil.aspx.cs</em></h5>
<p>En este <em>.cs</em> daremos valores a algunos elementos del <em>.aspx</em>, y además proporcionaremos métodos que rescatarán de sesión el ID del usuario y devolverán su nombre. Hay dos versiones para este método, uno devolverá el nombre tal cual, y el otro nos dará la posiblidad de devolver el nombre formateado para URL.</p>
<pre class="brush:csharp">
	protected void Page_Load(object sender, EventArgs e)
	{
		this.hTitle.InnerText = this.getUserName();

		Page.Title  = this.getUserName();

		lbUsuariosContacto.PostBackUrl = &quot;~/usuarios/&quot;   this.getUserName(true)   &quot;/contacto/&quot;;
		lbUsuariosContacto.Text  = this.getUserName();
	}

	public string getUserName()
	{
		Datos.Usuarios usu = new Datos.Usuarios();

		if (HttpContext.Current.Items.Contains(&quot;userid&quot;) &amp;&amp; HttpContext.Current.Items[&quot;userid&quot;].ToString() != &quot;-1&quot;)
		{
			return usu[Convert.ToInt32(HttpContext.Current.Items[&quot;userid&quot;])];
		}
		else
		{
			return &quot;user not found&quot;;
		}
	}

	public string getUserName(bool encode)
	{
		Datos.Usuarios usu = new Datos.Usuarios();

		if (HttpContext.Current.Items.Contains(&quot;userid&quot;))
		{
			return usu[Convert.ToInt32(HttpContext.Current.Items[&quot;userid&quot;])].ToLowerInvariant().Replace(&quot; &quot;, &quot;-&quot;);
		}
		else
		{
			return &quot;user not found&quot;;
		}
	}
</pre>
<h5><em>UsuariosContacto.cs</em></h5>
<p>Este <em>.cs</em> es bastante similar al anterior, así que no merece demasiados comentarios:</p>
<pre class="brush:csharp">
	protected void Page_Load(object sender, EventArgs e)
	{
		hTitle.InnerHtml  = getUserName();

		Page.Title  = this.getUserName();

		lbUsuariosPerfil.PostBackUrl = &quot;~/usuarios/&quot;   getUserName(true)   &quot;/&quot;;
		lbUsuariosPerfil.Text  = getUserName();
	}

	public string getUserName()
	{
		Datos.Usuarios usu = new Datos.Usuarios();

		if (HttpContext.Current.Items.Contains(&quot;userid&quot;))
		{
			return usu[Convert.ToInt32(HttpContext.Current.Items[&quot;userid&quot;])];
		}
		else
		{
			return &quot;user not found&quot;;
		}
	}

	public string getUserName(bool encode)
	{
		Datos.Usuarios usu = new Datos.Usuarios();

		if (HttpContext.Current.Items.Contains(&quot;userid&quot;) &amp;&amp; HttpContext.Current.Items[&quot;userid&quot;].ToString() != &quot;-1&quot;)
		{
			return usu[Convert.ToInt32(HttpContext.Current.Items[&quot;userid&quot;])].ToLowerInvariant().Replace(&quot; &quot;, &quot;-&quot;);
		}
		else
		{
			return &quot;user not found&quot;;
		}
	}
</pre>
<h4>Añadimos el <em>Global.asax</em></h4>
<p>Añadimos un nuevo elemento en el proyecto. El nuevo elemento será un Artchivo de aplicación global. No le cambiaremos el nombre: lo dejaremos como <em>&#8220;Global.asax&#8221;</em>.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/04/01-global-asax.png"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/04/01-global-asax.png" alt="Global.asax" title="01-global-asax" width="540" height="329" class="aligncenter size-full wp-image-427" /></a></p>
<h4>Configuramos las nuevas rutas</h4>
<p>Antes que nada, debemos agregar la librería <em>&#8220;System.Web.Routing&#8221;</em>.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/04/02-system-web-routing.png"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/04/02-system-web-routing.png" alt="System.Web.Routing" title="02-system-web-routing" width="503" height="390" class="aligncenter size-full wp-image-428" /></a></p>
<p>Programaremos nuestra propia función para aplicar el enrutamiento. La llamaremos <em>&#8220;ApplyRouting&#8221;</em>:</p>
<pre class="brush:csharp">
	private void ApplyRouting(RouteCollection Routes)
	{
		Routes.Add(new Route(&quot;&quot;, new RouteHandler(&quot;~/Default.aspx&quot;)));
		Routes.Add(new Route(&quot;inicio/&quot;, new RouteHandler(&quot;~/Default.aspx&quot;)));
		Routes.Add(new Route(&quot;buscar/&quot;, new RouteHandler(&quot;~/Buscar.aspx&quot;)));
		Routes.Add(new Route(&quot;usuarios/&quot;, new RouteHandler(&quot;~/Usuarios.aspx&quot;)));
		Routes.Add(new Route(&quot;usuarios/{username}/&quot;, new RouteHandler(&quot;~/UsuariosPerfil.aspx&quot;)));
		Routes.Add(new Route(&quot;usuarios/{username}/contacto/&quot;, new RouteHandler(&quot;~/UsuariosContacto.aspx&quot;)));
	}
</pre>
<p>Y la llamaremos desde el evento <em>Application_BeginRequest</em>:</p>
<pre class="brush:csharp">
	protected void Application_BeginRequest(object sender, EventArgs e)
	{
		ApplyRouting(RouteTable.Routes);
	}
</pre>
<p>Lo que hacemos es, básicamente; añadir nuevas rutas creadas por nosotros a la tabla de rutas de nuestra aplicación. Hay varias cosas destacables:</p>
<ol>
<li>El primer parámetro es la nueva ruta. Si escribimos el valor entre llaves, será un parámetro. Los parámetros que antes enviábamos por <em>GET</em> deberían ser sustituídos por estos.</li>
<li>Estamos creando instancias de RouteHandler. Esta clase no existe en la Api de C#, la tenemos que programar nosotros y será donde añadiremos toda la lógica de redireccionamiento.</li>
<li>Como la clase RouteHandler la programamos nosotros, tenemos ciertas ventajas. En este caso, pasamos como parámetro del constructor el archivo al cual redirigimos. No tendría por qué ser así, pero como una de las características de nuestras URL es que siempre redirigen a un único archivo; este sistema nos viene bastante bien.</li>
</ol>
<h4>Programamos la lógica de redireccionamiento</h4>
<p>Vamos a crear ahora la clase <em>Routing/RouteHandler.cs</em>. Esta clase, deberá heredar de <em>IRouteHandler</em> y por tanto deberá incorporar un método público llamado <em>GetHttpHandler</em>, que recibirá un único parámetro que es un <em>RequestContext</em> y que retornará un <em>IHttpHandler</em>.</p>
<p>En este método pasaran escencialmente dos cosas: por una parte, se meterán los parámetros recibidos en sesión. Por otra, se retornará un <em>IHttpHandler</em> que construiremos usando la ruta del <em>.aspx</em> al que queremos redirigir.</p>
<pre class="brush:csharp">
	public IHttpHandler GetHttpHandler(RequestContext requestContext)
	{
		/*
		 * Tratamos los parámetros de la URL:
		 * Si es el nombre de usuario, buscamos su ID y lo metemos en sesión.
		 * Si no, símplemente lo metemos en sesión
		 */
		foreach (KeyValuePair&lt;string, object&gt; val in requestContext.RouteData.Values)
		{
			if (val.Key == &quot;username&quot;)
			{
				Datos.Usuarios usu = new Datos.Usuarios();
				int userid = usu.search(val.Value.ToString());
				requestContext.HttpContext.Items[&quot;userid&quot;] = userid;
			}

			requestContext.HttpContext.Items[val.Key] = val.Value;
		}

		return (Page) BuildManager.CreateInstanceFromVirtualPath(VirtualPath, typeof(Page));
	}
</pre>
<p>Añadimos además un constructor y una variable global para el parámetro que indica el archivo al que redirigimos.</p>
<pre class="brush:csharp">
	string VirtualPath = string.Empty;

	public RouteHandler(string path)
	{
		this.VirtualPath = path;
	}
</pre>
<p>Hecho esto, nuestras nuevas rutas ya deberían estar funcionando. Sólo nos queda un detalle.</p>
<h4>Ignorando rutas</h4>
<p>Generalmente, no sólo nos va a interesar añadir rutas a nuestra aplicación, sino tambien quitarlas. Por ejemplo, no es una mala idea que se ignoren las rutas directas a un <em>.aspx</em>, o aquellas rutas que no acaben con el carácter <em>&#8220;/&#8221;</em> (para tener un sistema de rutas uniforme). Vamos a programar una función en <em>Global.asax</em>, a la cual llamaremos justo antes de <em>ApplyRouting</em> y que se encargará de comprobar si nuestra ruta debe ser ignorada y, en ese caso, redirigir a <em>/inicio/</em>.</p>
<p>El método <em>Application_BeginRequest</em> en <em>Global.asax</em> queraría de la siguiente forma:</p>
<pre class="brush:csharp">
	protected void Application_BeginRequest(object sender, EventArgs e)
	{
		Redirect();
		ApplyRouting(RouteTable.Routes);
	}
</pre>
<p>El método <em>Redirect</em>:</p>
<pre class="brush:csharp">
	private void Redirect()
	{
		string url = Request.Url.ToString();

		if (url.Contains(&quot;.aspx&quot;))
		{
			Response.Redirect(&quot;~/inicio/&quot;);
		}

		if (url[url.Length - 1] != '/' &amp;&amp; !url.Contains(&quot;?&quot;))
		{
			Response.Redirect(url + &quot;/&quot;);
		}
	}
</pre>
<h4>Descarga el código fuente</h4>
<p>Sé que me odias por no haber puesto este archivo al principio, pero más vale tarde que nunca ¿no?.</p>
<p><a href='http://www.juanmasantoyo.es/wp-content/uploads/2010/04/JuanmaSantoyoSeoFriendly.zip'>Código fuente</a>.</p>
<h3>¡Hemos acabado!</h3>
<p>Como véis, en asp.Net el enrutamiento Seo Friendly se reduce a dos clases: <em>Global.asax</em> y el manejador de rutas. Es bastante simple, y no requiere demasiado tiempo de implementación. Los beneficios de usar este tipo de enrutamiento son múltiples, desde aspectos de seguridad, hasta aspectos de usuabilidad y posicionamiento en buscadores. ¡Ya no hay excusa para no implementarlo!.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/04/06/enrutamiento-seo-friendly-con-asp-net/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducción al desarrollo sobre Microsoft Surface</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/04/06/introduccion-al-desarrollo-para-microsoft-surface/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/04/06/introduccion-al-desarrollo-para-microsoft-surface/#comments</comments>
		<pubDate>Tue, 06 Apr 2010 06:15:28 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[surface]]></category>
		<category><![CDATA[microsoft]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=158</guid>
		<description><![CDATA[Microsoft Surface (Surface a partir de ahora) es sin duda un desafío para los programadores. Acostumbrados a entornos gráficos basados en respuestas al ratón, una interfaz de usuario multitáctil nos plantea un nuevo reto a la mayoría de nosotros.

En este artículo, pretendo dos cosas: por una parte, informarte de qué necesitas para comenzar a desarrollar y cómo obtenerlo. Por otra parte, facilitarte esa documentación que a todos nos va tan bien para empezar con una nueva tecnología. Así que vamos a ello.]]></description>
			<content:encoded><![CDATA[<p>Microsoft Surface (Surface a partir de ahora) es sin duda un desafío para los programadores. Acostumbrados a entornos gráficos basados en respuestas al ratón, una interfaz de usuario multitáctil nos plantea un nuevo reto a la mayoría de nosotros.</p>
<p>En este artículo, pretendo dos cosas: por una parte, informarte de qué necesitas para comenzar a desarrollar y cómo obtenerlo. Por otra parte, facilitarte esa documentación que a todos nos va tan bien para empezar con una nueva tecnología. Así que vamos a ello.<br />
<span id="more-158"></span><br />
Lo primero que debes saber, es que una aplicación para Surface no es más que una aplicación WPF o XNA. Por si no lo sabías, WPF es un entorno muy potente para desarrollar aplicaciones de escritorio orientadas a los nuevos entornos gráficos de Windows Vista y Windows 7. XNA es un entorno para desarrollo de videojuegos también facilitado por Microsoft. Si has jugado con la Xbox 360 te habrás preguntado ¿de dónde salen los tantísimos juegos del bazar? Pues bien, la mayoría están desarrollados por compañías independientes con XNA.</p>
<p>Obviamente, optar por WPF o XNA dependerá de nuestra aplicación. Si necesitamos un motor rico en controles de usuario, optaríamos por WPF. Si necesitamos un motor potente en la renderización de gráficos 3D, optaríamos por XNA. Depende de las necesidades de nuestra aplicación.</p>
<p>En este artículo, pretendo dos cosas: por una parte, informarte de qué necesitas para comenzar a desarrollar y cómo obtenerlo. Por otra parte, facilitarte esa documentación que a todos nos va tan bien para empezar con una nueva tecnología. Así que vamos a ello.</p>
<p>Lo primero que debes saber, es que una aplicación para Surface no es más que una aplicación WPF o XNA. Por si no lo sabías, WPF es un entorno muy potente para desarrollar aplicaciones de escritorio orientadas a los nuevos entornos gráficos de Windows Vista y Windows 7. XNA es un entorno para desarrollo de videojuegos también facilitado por Microsoft. Si has jugado con la Xbox 360 te habrás preguntado ¿de dónde salen los tantísimos juegos del bazar? Pues bien, la mayoría están desarrollados por compañías independientes con XNA.Obviamente, optar por WPF o XNA dependerá de nuestra aplicación. Si necesitamos un motor rico en controles de usuario, optaríamos por WPF. Si necesitamos un motor potente en la renderización de gráficos 3D, optaríamos por XNA. Depende de las necesidades de nuestra aplicación.</p>
<h3>Instalación del entorno de desarrollo</h3>
<p>Para empezar, un detalle importante es nuestro sistema operativo: El SDK de Surface no funcionará en Windows XP, necesitaremos Windows Vista o superior.</p>
<p>Bien, empecemos a instalar los programas necesarios. Antes de empezar, no estaría mal asegurarse de que tenemos instalada la última versión del .Net Framework (3.5 SP1 en estos momentos).</p>
<p>La primera herramienta que debemos conseguir es un Visual Studio. Como sabrás, Visual Studio es un IDE desarrollado por Microsoft y orientado al desarrollo de aplicaciones en .Net. Si no lo tienes y eres estudiante universitario, puedes hacerte con una licencia de estudiante. Esta licencia es totalmente gratuita y sólo necesitaras proporcionar tu identificación como estudiante. Puedes obtenerla aquí: <a href="https://www.dreamspark.com/Products/Product.aspx?productid=24">Microsoft Visual Studio</a>.</p>
<p>Cuando tengamos el Visual Studio instalado, deberemos instalar el Framework de XNA (independientemente de que queramos desarrollar con WPF). Lo podemos obtener de aquí: <a href="http://www.microsoft.com/downloads/details.aspx?familyid=15fb9169-4a25-4dca-bf40-9c497568f102&#038;displaylang=en.">Microsoft XNA Framework</a>.</p>
<p>Finalmente, instalamos el SDK de Surface. Lo encontramos aquí: <a href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&#038;FamilyID=3db8987b-47c8-46ca-aafb-9c3b36f43bcc">Microsoft Surface SDK</a>.</p>
<p>Con este software instalado, ya estamos listos para abrir el Visual Studio y crear un nuevo proyecto de Surface, no sin antes ejecutar el emulador de Surface que viene con el SDK. De esta forma, al depurar proyectos desde Visual Studio, se ejecutarán en el emulador.</p>
<p>Debes saber, además; que si conectas más de un ratón por USB el emulador los considerará dedos diferentes. ¡Eso es, soporte multitáctil en tu ordenador!.</p>
<h3>Recursos de documentación para empezar</h3>
<p>Ya tenemos todo lo necesario para empezar a desarrollar aplicaciones de Surface. Ahora, sólo nos falta algo de documentación que nos oriente para empezar a hacer cosas.</p>
<h4>Developing for Microsoft Surface</h4>
<p>Pero ¿dónde nos estamos metiendo realmente? En esta conferencia de Microsoft se ilustra cómo es el desarrollo de aplicaciones en Surface.<br />
<a href="http://channel9.msdn.com/pdc2008/PC17/">Developing for Microsoft Surface</a>.</p>
<h4>Hola Mundo Surface con WPF</h4>
<p>Siguiendo en la línea anterior, este artículo me ha aclarado algunos conceptos generales más a la hora de afrontar el desarrollo con Surface. Interesante sobre todo porque habla algo de los nuevos eventos de contacto de Surface.<br />
<a href="http://www.luisguerrero.net/post/2009/03/16/Hola-Mundo-Surface-con-WPF.aspx">Hola Mundo Surface con WPF</a>.</p>
<h4>MSDN .Net Framework Developer Center</h4>
<p>Pero vamos, ya está bien de conceptos generales, ¿verdad? Seguro que ya tienes ganas de meterle mano a Surface.</p>
<p>En MSDN nos facilitan información y ejemplos varios para empezar a programar algunas cosas. ¡Suerte!.<br />
<a href="http://msdn.microsoft.com/en-us/library/ee804767.aspx">MSDN .Net Framework Developer Center</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/04/06/introduccion-al-desarrollo-para-microsoft-surface/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>XML dinámicos con asp.Net</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/03/16/xml-dinamicos-con-asp-net/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/03/16/xml-dinamicos-con-asp-net/#comments</comments>
		<pubDate>Tue, 16 Mar 2010 19:04:33 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[asmx]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[webservice .net]]></category>
		<category><![CDATA[xml dinamicos]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=397</guid>
		<description><![CDATA[Desde que me inicié en el asp.Net (no hace demasiado de eso) me he estado preguntando cómo se podría hacer una llamada al servidor que devolviese un contenido XML dinámico. Dicho de otra forma, lo que yo quería era generar un contenido XML en base a un parámetro enviado por GET o POST. Estos XML son necesarios para cualquier aplicación basada en Ajax que se precie, además de ser especialmente útiles para otras situaciones (como por ejemplo, compartir contenido interno a un destinatario externo).

Pues bien, hace un par de días me surgió la necesidad y investigué un poco al respecto. En realidad, la solución que nos propone asp.Net no está nada mal: un archivo asmx que actúa como WebService.]]></description>
			<content:encoded><![CDATA[<p>Desde que me inicié en el asp.Net (no hace demasiado de eso) me he estado preguntando cómo se podría hacer una llamada al servidor que devolviese un contenido <em>XML</em> dinámico. Dicho de otra forma, lo que yo quería era generar un contenido XML en base a un parámetro enviado por GET o POST. Estos <em>XML</em> son necesarios para cualquier aplicación basada en <a href="http://www.juanmasantoyo.es/index.php/category/ajax/">Ajax</a> que se precie, además de ser especialmente útiles para otras situaciones (como por ejemplo, compartir contenido interno a un consumidor externo).</p>
<p>Pues bien, hace un par de días me surgió la necesidad y investigué un poco al respecto. En realidad, la solución que nos propone <em>.Net</em> no está nada mal: un archivo <em>.asmx</em> que actúa como <em>WebService</em>.<br />
<span id="more-397"></span></p>
<h3>Sobre los <em>.asmx</em></h3>
<p>De la misma forma que podemos añadir archivos <em>.aspx</em> a un proyecto web, también podemos añadir archivos <em>.asmx</em>. Estos archivos son la base de cualquier proyecto de <em>WebService</em> que desarrollemos en <em>.Net</em>, pero también podemos usarlos en los proyectos web normales.</p>
<h3>¿Cómo se usan los <em>.asmx</em>?</h3>
<p>El uso de los <em>.asmx</em> es simple: básicamente, lo que debemos hacer es crear un método, que devuelva un valor y que tenga la etiqueta [WebMethod]. Al final, la llamada a servidor: &#8220;http://&lt;ruta al asmx&gt;/&lt;nombre del método&gt;/&lt;parámetros get si hay&gt;&#8221; nos devolverá el resultado devuelto por el método.</p>
<p>Por supuesto, el método puede tener parámetros, que enviaremos por <em>GET</em> o por <em>POST</em>; en cuyo caso, al hacer la llamada los parámetros enviados deberán tener el mismo nombre que el parámetro en el método.</p>
<p>Es importante destacar que si queremos enviar parámetros por <em>GET</em> o <em>POST</em>, deberemos activar ambos protocolos en el <em>Web.config</em> de nuestra aplicación.</p>
<h3>Un ejemplo</h3>
<p>La mejor forma de ver cómo funciona un <em>.asmx</em> es viendo un pequeño ejemplo. Con poco esfuerzo podremos hacer algunas pruebas.</p>
<h4>Crear el proyecto</h4>
<p>Sólo necesitaremos crear un nuevo proyecto web en nuestro Visual Studio. Nos creará por defecto un <em>.aspx</em>, pero no nos interesa demasiado.</p>
<h4>Crear el asmx</h4>
<p>Añadiremos en el proyecto web un nuevo elemento, que será un Servicio web. Lo encontrarás entre los posibles elementos de la categoría &#8220;Web&#8221;. Lo llamaremos &#8220;<em>test.asmx</em>&#8220;.</p>
<p>Cuando tengamos nuestro <em>.asmx</em> creado, lo estableceremos como la página inicial de nuestro proyecto (es una opción que aparecerá si clicamos con el botón derecho en el <em>.asmx</em>).</p>
<h4>Un nuevo método en el <em>.asmx</em></h4>
<p>En el <em>.asmx</em> ya tenemos un método creado: <em>HelloWorld</em>. Es muy ilustrativo, ya que nos indica dos cosas: la primera, que nuestros métodos deberán tener al principio la etiqueta <strong>[WebMethod]</strong>. La segunda, que el valor retornado será lo que mostrará nuestro <em>WebService</em> al realizar una petición al método.</p>
<p>Vamos a programar un método más bien absurdo, pero que nos permitirá ver cómo funciona el envío de parámetros:</p>
<pre class="brush:csharp">
	[WebMethod]
	public string ReturnThisString(string str)
	{
		return str;

	}
</pre>
<p>Hay dos cosas a destacar:</p>
<ol>
<li>El parámetro que recibe este método se llama <strong>str</strong>.</li>
<li>El resultado que genera este método, es un <em>string</em>.</li>
</ol>
<h3>Activamos los protocolos <em>GET</em> y <em>POST</em></h3>
<p>Como dije unas líneas más arriba, debemos activar los protocolos de envío <em>GET</em> y <em>POST</em> si queremos usarlos en nuestro <em>WebService</em>. Todo lo que debemos hacer es incluir <strong>dentro</strong> del nodo <em>&lt;system.web/&gt;</em> de nuestro <em>Web.config</em> las siguientes líneas:</p>
<pre class="brush:xml">
	&lt;webServices&gt;
		&lt;protocols&gt;
			&lt;add name=&quot;HttpGet&quot; /&gt;
			&lt;add name=&quot;HttpPost&quot; /&gt;
		&lt;/protocols&gt;
	&lt;/webServices&gt;
</pre>
<h4>Probamos el <em>WebService</em></h4>
<p>Y toca inicar una depuración. La primera vez que lo hagamos nos pedirá que activemos el modo debug. Le decimos que sí, y arrancará el <em>.asmx</em>.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-01-e1268766894973.png"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-01-e1268766894973.png" alt="Métodos del WebService" title="Métodos del WebService" width="450" height="131" class="aligncenter size-full wp-image-403" /></a></p>
<p>Lo que veremos, será un resumen de los métodos que tiene el <em>.asmx</em> (esto no se vería en un entorno de producción). Podemos clicar en el nombre de nuestro método &#8220;<em>ReturnThisString</em>&#8221; para que nos muestre un pequeño formulario donde indicaremos el valor del parámetro &#8220;<em>str</em>&#8220;. Al enviarlo, veremos el resultado de nuestro método de <em>WebService</em>.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-02-e1268766971605.png"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-02-e1268766971605.png" alt="Formulario de envío de parámetros" title="Formulario de envío de parámetros" width="450" height="244" class="aligncenter size-full wp-image-404" /></a></p>
<p>Hay varias cosas interesantes en las que fijarse ahora:</p>
<ol>
<li>
		El resultado devuelto es un XML.	</p>
<p>		Sea cual sea el resultado, el asmx siempre nos dará una respuesta XML.
	</li>
<li>
		La ruta de la página.</p>
<p>		Como ves, la url de este xml es: &#8220;http://&lt;ruta al asmx&gt;/&lt;nombre del método&gt;/&lt;parámetros get si hay&gt;&#8221;. Esta es la dirección a la que accederemos para obtener resultados de nuestro <em>WebService</em>, ya sea con <em>Ajax</em> o con otra tecnología.
	</li>
<li>
		El nodo <em>string</em>.</p>
<p>		El resultado del método viene, en realidad, dentro de un nodo llamado <em>string</em>. Esto es, efectívamente, el tipo del dato devuelto. ¿imaginas lo que pasaría si en vez de un <em>string</em>, devolvemos una lista de <em>strings</em>? Efectivamente, el <em>XML</em> resultante sería una lista de nodos <em>string</em>.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-03-e1268766951190.png"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-03-e1268766951190.png" alt="Resultado de una llamada al método ReturnThisString" title="Resultado de una llamada al método ReturnThisString" width="450" height="114" class="aligncenter size-full wp-image-405" /></a>
	</li>
</ol>
<h4>Generamos un <em>XML</em> como respuesta del método</h4>
<p>Como ves, los <em>WebServices</em> <em>.asmx</em> no son demasiado complicados, aunque por el momento seguimos teniendo un pequeño problema: los <em>XML</em> que generamos como resultado son generados automáticamente y no tenemos control sobre ellos. Vamos a poner solución a esto.</p>
<p>La cuestión es que si en lugar de un <em>string</em>, devolvemos un objeto <em>XmlDocument</em>, el resultado devuelto por el <em>WebService</em> será el contenido del <em>XmlDocument</em> tal cual. Por lo tanto, se podría decir que el proceso para generar respuestas <em>XML</em> personalizadas (la razón de este artículo) es el siguiente:</p>
<ol>
<li>Creamos un método en el <em>.asmx</em> que devuelva un objeto <em>XmlDocument</em>.</li>
<li>Obtenemos todos los datos que queramos devolver.</li>
<li>Los metemos en un <em>XmlDocument</em>.</li>
<li>Retornamos el <em>XmlDocument</em>.</li>
</ol>
<h4>Un último ejemplo</h4>
<p>Vamos a crear un último ejemplo: un pequeño método que nos introducirá en la creación de <em>XML</em> dinámicos:</p>
<pre class="brush:csharp">
	[WebMethod]
	public XmlDocument ReturnXml()
	{
		XmlDocument xml = new XmlDocument();

		XmlNode rootNode = xml.CreateElement("RespuestaXml");
		XmlNode txtNode = xml.CreateTextNode("Xml generado automáticamente");
		XmlNode subNode = xml.CreateElement("HolaMundo");
		XmlNode commentNode = xml.CreateComment("Esto es un comentario");

		subNode.AppendChild(commentNode);
		rootNode.AppendChild(txtNode);
		rootNode.AppendChild(subNode);
		xml.AppendChild(rootNode);

		return xml;
	}
</pre>
<p>Esto generaría el siguiente resultado:</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-04-e1268766930458.png"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/03/XmlDinamicosAspNet-04-e1268766930458.png" alt="Resultado de una llamada al método ReturnXml" title="Resultado de una llamada al método ReturnXml" width="450" height="211" class="aligncenter size-full wp-image-406" /></a></p>
<h3>Descargar el ejemplo</h3>
<p>Puedes descargar el ejemplo si algo no te ha quedado claro. Recuerda también que puedes dejar comentarios.</p>
<p><a href='http://www.juanmasantoyo.es/wp-content/uploads/2010/03/JuanmaSantoyoXmlDinamicos.zip'>JuanmaSantoyoXmlDinamicos</a></p>
<h3>¡Hemos terminado!</h3>
<p>Y de momento no hay mucho más que decir. Con este ejemplo, hemos tocado un tema especialmente importante para la mayoría de proyectos web, ya que los <em>XML</em> dinámicos son importantes para las funcionalidades <em>Ajax</em> y para comunicarnos con otras aplicaciones externas. ¿Aún no tienes RSS en tu sitio web? <a href="http://www.rssboard.org/rss-specificationg">¡A qué esperas!</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/03/16/xml-dinamicos-con-asp-net/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Generación de colores intermedios con resultados multicolor</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/02/24/generacion-de-colores-intermedios-con-resultados-multicolor/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/02/24/generacion-de-colores-intermedios-con-resultados-multicolor/#comments</comments>
		<pubDate>Wed, 24 Feb 2010 15:00:35 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[colores javascript]]></category>
		<category><![CDATA[degradados javascript]]></category>
		<category><![CDATA[mezclar colores javascript]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=355</guid>
		<description><![CDATA[No hace mucho se comenté una técnica para calcular los colores intermedios entre dos colores cualesquiera. Lo que haremos en esta ocasión es ampliar el script que creamos entonces para que se puedan especificar más de dos colores.

Multi-Colores intermedios.
La idea
La idea es sencilla: si tenemos una función para calcular los intermedios entre dos colores, podemos [...]]]></description>
			<content:encoded><![CDATA[<p>No hace mucho se comenté una técnica para calcular los colores intermedios entre dos colores cualesquiera. Lo que haremos en esta ocasión es ampliar el script que creamos entonces para que se puedan especificar más de dos colores.<br />
<span id="more-355"></span><br />
<a href='http://www.juanmasantoyo.es/wp-content/uploads/2010/02/multi-colores.js'>Multi-Colores intermedios</a>.</p>
<h3>La idea</h3>
<p>La idea es sencilla: si tenemos una función para calcular los intermedios entre dos colores, podemos usar esa función varias veces y de esta forma obtener un resultado multicolor. Donde antes íbamos del azul al rojo, ahora podremos ir del azul al rojo, y después del rojo al verde; de forma que lo que tenemos es una sucesión de colores que va del azul al verde pasando por el rojo.</p>
<p>¿Cómo lo haremos? Fácil. En realidad, no hay que programar nada nuevo sobre mezclas de colores, todo lo que haremos será una función que gestionará diversas llamadas a la mezcla de dos colores que ya teníamos.</p>
<h3>Aclaramos un par de detalles</h3>
<ul>
<li>Crearemos una función llamada <em>getGradientMultiColors</em>, que recibirá un array con los colores básicos de nuestro degradado. Por ejemplo, si queremos un degradado de azul a verde, pasando por el rojo, el array contendrá el color azul, el rojo y el verde (por ese orden). Esta función también recibirá la cantidad de colores que queremos al final del cálculo (incluyendo los colores básicos).</li>
<li>Se hará una gestión de los colores resultantes que eliminará repeticiones de colores básicos, y calculará la cantidad de colores que se obtendrán en cada llamada a <em>getGradientColors</em>.</li>
<li>La política para el cálculo de colores será la siguiente: Se calcularán una cantidad de total de colores / total de colores basicos, redondeando a la baja. Los colores que falten para completar la cantidad total de colores, se generarán repitiendo los colores al inicio y al final de la sucesión de colores resultante.</li>
</ul>
<h3>Programamos la función</h3>
<p>Bueno, al lío:</p>
<pre class="brush:js">
function getGradientMiltiColours(colours, total)
{
	var res = new Array();
	var temp = new Array();

	var gradientZones = Math.floor(total / (colours.length - 1));

	for(var i = 0; i < (colours.length - 1); i++)
	{
		temp = getGradientColours(colours[i], colours[i + 1], gradientZones);

		// Si no es el primer cálculo de colores, quitamos el primer elemento para evitar repeticiones.
		if(i != 0)
		{
			temp.shift();
		}

		res = res.concat(temp);
	}

	var toAdd = (total - res.length);

	/*
		Si queda un número par de colores por añadir, añadimos la mitad al inicio y la mitad al final.
		Si no, restamos uno, añadimos la mitad al principio y la mitad al final, y finalmente uno más al final.
	*/

	var repeatLast = false;
	if(toAdd % 2 != 0)
	{
		toAdd --;
		repeatLast = true;
	}

	var i = 0;
	toAdd = toAdd / 2;
	while(i < toAdd)
	{
		res.unshift(res[0]);
		res.push(res[res.length - 1]);
		i++;
	}

	if(repeatLast == true)
	{
		res.push(res[res.length - 1]);
	}

	return res;
}
</pre>
<h3>¡Hemos terminado!</h3>
<p>Bueno, en realidad no hemos hecho nada del otro mundo, pero es una mejora que se me ocurrió poco después de publicar el artículo original y valía la pena hacerla.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/02/24/generacion-de-colores-intermedios-con-resultados-multicolor/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Colores intermedios con JavaScript</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/02/12/colores-intermedios-con-javascript/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/02/12/colores-intermedios-con-javascript/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 18:09:37 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[colores javascript]]></category>
		<category><![CDATA[degradados javascript]]></category>
		<category><![CDATA[mezclar colores javascript]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=314</guid>
		<description><![CDATA[Hace poco, un compañero me preguntó sobre encontrar varios colores intermedios entre dos colores, de forma que un color pueda transformarse gradualmente en el otro. Esto es lo que se hace, por ejemplo, para averiguar los colores que forman un degradado o para calcular el color resultante al solapar dos colores con cierta transparencia.

Lo que vamos a hacer es crear un pequeño script en JavaScript que se encargará de calcular varios colores intermedios entre dos colores cualesquiera.]]></description>
			<content:encoded><![CDATA[<p>Hace poco, un compañero me preguntó sobre encontrar varios colores intermedios entre dos colores, de forma que un color pueda transformarse gradualmente en el otro. Esto es lo que se hace, por ejemplo, para averiguar los colores que forman un degradado o para calcular el color resultante al solapar dos colores con cierta transparencia.</p>
<p>Lo que vamos a hacer es crear un pequeño script en JavaScript que se encargará de calcular varios colores intermedios entre dos colores cualesquiera.<br />
<span id="more-314"></span></p>
<p><a href='http://www.juanmasantoyo.es/wp-content/uploads/2010/02/colores.js'>Colores intermedios</a>.</p>
<p>Bien, en realidad, es un proceso muy sencillo, ya que los colores son en esencia, números.</p>
<h3>Sobre los colores como números</h3>
<p>Cualquier color en pantalla, se basa en tres componentes: la cantidad de rojo, la cantidad de verde y la cantidad de azul. Un color especificado de esta forma, está siguiendo el patrón RGB. Los diferentes valores de las componentes pueden ir desde el 0 hasta el 255.</p>
<p>Puesto que cada componente del color tiene exactamente 256 valores posibles, se pueden representar con un valor hexadecimal de dos cifras, desde el 0 hasta el FF. De hecho, lo más normal es representarlos mediante tres valores hexadecimales. Esto nos da un número hexadecimal de seis cifras, donde las dos primeras son la componente R (cantidad de rojo), los dos segundos son la componente G (la cantidad de verde) y los dos últimos la componente B (la cantidad de azul).</p>
<p>Por ejemplo, el rojo se representaría así: FF0000 (255 de rojo, 0 de verde y 0 de azul).</p>
<p>Con lo cual, un color no es más que un número. Con la calculadora de tu sistema operativo puedes hacer una conversión de hexadecimal a decimal y ver qué valor decimal corresponde al color rojo. Se trata del 16711680.</p>
<h3>La idea</h3>
<p>Bien, ahora que sabemos que un color es un número, podemos simplificar mucho el problema al que nos enfrentamos.</p>
<p>Cualquiera con nociones de matemáticas básicas, sabría decir que el valor intermedio entre el 10 y el 20 es el 15. Los colores intermedios se calculan de la misma forma. Cambiaremos el 10 y el 20 por nuestras componentes.</p>
<p>Debemos tener en cuenta que debemos mezclar cada componente por separado. De forma que el punto intermedio entre rojos, el punto intermedio entre verdes y el punto intermedio entre azules nos dará el color intermedio entre nuestros dos colores.</p>
<h3>Un script para calcular colores intermedios</h3>
<p>Antes de empezar a programar nada, lo de siempre: hay que saber más o menos cómo vamos a hacer las cosas.</p>
<ul>
<li>En principio, trabajaremos con los colores en su notación hexadecimal. Por lo tanto, necesitamos una pequeña función que se encargue de separar las componentes, y de convertirlas a un valor decimal. Esta función se llamará getColorComponents.</li>
<li>Necesitaremos una función que se dedique a calcular los intervalos necesarios entre dos componentes de color. Es decir, encontraremos todos los intervalos de cada componente de color por separado. Esta función se llamará getGradientComponents.</li>
<li>Por lo tanto, lo único que nos falta es una función que lo integre todo y que sea capaz de retornar una lista de cadenas de texto, cada una de las cuales representará un intervalo de color en codificado en hexadecimal. Esta función se llamará getGradientColors.</li>
<li>Sólo un detalle más: El primer y último color, son un intervalo más. Esto es que si pedimos tres colores, sólo calculará uno adicional: el valor central.</li>
</ul>
<h3>Programamos el Script</h3>
<h4>La función getColorComponents</h4>
<pre class="brush:js">
function getColorComponents(numero)
{
	var res = new Array();

	res[0] = parseInt(&quot;0x&quot; + numero.substr(0, 2));
	res[1] = parseInt(&quot;0x&quot; + numero.substr(2, 2));
	res[2] = parseInt(&quot;0x&quot; + numero.substr(4, 2));

	return res;
}
</pre>
<p>Como veis, nos limitamos a separar los componentes. Lo único destacable es cómo realiza la conversión a hexadecimal. En JavaScript, los números que empiezan con <em>0x</em> se consideran hexadecimales.</p>
<h4>La función getGradientComponents</h4>
<pre class="brush:js">
function getGradientComponents(n1, n2, z)
{
	var i = 0;
	var n = 0;
	var res = new Array();

	n = (n1 - n2) / (z - 1);

	for(i = 0; i &lt; z; i++)
	{
		res[i] = n2 + (n * ((z - 1) - i));
		res[i] = Math.floor(res[i]);
		res[i] = res[i].toString(16);

		if(res[i].length &lt; 2) res[i] = &quot;0&quot; + res[i];
	}

	return  res;
}
</pre>
<p>Esta función tiene como parámetros las componentes iniciales y finales, y el número de valores intermedios que hay que sacar. El cálculo como veis es sencillo.</p>
<h4>La función getGradientColors</h4>
<pre class="brush:js">
function getGradientColors(firstColor, lastColor, gradientZones)
{
	var components1 = getColorComponents(firstColor);
	var components2 = getColorComponents(lastColor);

	var i = 0;
	var colors = new Array();
	var res = new Array();

	for(i = 0; i &lt; components1.length; i++)
	{
		colors[i] = getGradientComponents(components1[i], components2[i], gradientZones);
	}

	for(i = 0; i &lt; gradientZones; i++)
	{
		res[i] = colors[0][i] + colors[1][i] + colors[2][i];
	}

	return res;
}
</pre>
<p>Esta función gestiona las dos anteriores: primero separa cada color en sus componentes, después obtiene los puntos intermedios por componente y por último genera un <em>string</em> que representa los nuevos colores en hexadecimal.</p>
<p>Los resultados se devuelven en un <em>array</em>. Donde el primer elemento es el primer color, el último elemento es el segundo color; y todos los elementos intermedios son colores calculados.</p>
<h3>¡Hemos terminado!</h3>
<p>Puede que inicialmente sea complicado hacerse a la idea de que los colores funcionan como los números, pero una vez que ese concepto está claro, es fácíl trabajar con ellos y transformarlos.</p>
<p>Lo que hemos trabajado con este script es mezcla de colores, lo cual es muy potente para generar muchos tipos de efectos. En esta ocasión, nos hemos limitado a una mezcla progresiva, pero como siempre, las posiblidades son infinitas.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/02/12/colores-intermedios-con-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>El array arguments de JavaScript</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/02/09/el-array-arguments-de-javascript/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/02/09/el-array-arguments-de-javascript/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 11:00:02 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[argunents]]></category>
		<category><![CDATA[array arguments]]></category>
		<category><![CDATA[parametros]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=283</guid>
		<description><![CDATA[Normalmente los lenguajes de programación aplican ciertos controles sobre los argumentos que se pasan a una función:

<ul>
	<li>¿Se pasan los mismos parámetros que están especificados?</li>

	<li>¿Si se pasan menos parámetros, los que faltan tienen especificados valores por defeto?</li>

	<li>¿Los tipos coinciden?</li>
</ul>

Este tipo de cosas.

En JavaScript no es así. JavaScript no aplica ningún tipo de control sobre los parámetros que se le pasan, y en principio puedes pasar más parámetros de los especificados, o menos; a cualquier función. Pero JavaScript tiene el array arguments.]]></description>
			<content:encoded><![CDATA[<p>Normalmente los lenguajes de programación aplican ciertos controles sobre los argumentos que se pasan a una función:</p>
<ul>
<li>¿Se pasan los mismos parámetros que están especificados?</li>
<li>¿Si se pasan menos parámetros, los que faltan tienen especificados valores por defeto?</li>
<li>¿Los tipos coinciden?</li>
</ul>
<p>Este tipo de cosas.</p>
<p>En JavaScript no es así. JavaScript no aplica ningún tipo de control sobre los parámetros que se le pasan, y en principio puedes pasar más parámetros de los especificados, o menos; a cualquier función. Pero JavaScript tiene el array arguments.<br />
<span id="more-283"></span><br />
El array arguments es un array que tenemos en todas las funciones de JavaScript y que contiene los parámetros que se han pasado a la función.<br />
Por ejemplo, si invocamos a una función de esta manera:</p>
<pre class="brush:js">
mi_funcion("param1", "param2", "param3", "param4");
</pre>
<p>El array arguments (que será accesible desde cualquier parte de mi_funcion) contendrá:</p>
<pre class="brush:js">
[
	"param1"
	, "param2"
	, "param3"
	, "param4"
]
</pre>
<h3>Nuestro control de parámetros</h3>
<p>En las ocasiones en que necesitemos realizar un control de parámetros, podemos hacer un par de coas:</p>
<h4>Detectar que se estén pasando un número concreto de parámetros</h4>
<p>El array arguments es un array como cualquier otro y también tiene la propiedad <em>length</em>. El valor <em>arguments.length</em> nos dirá cuántos parámetros se han enviado y notros podemos acuar en consecuencia:</p>
<pre class="brush:js">
function mi_funcion(param1, param2, param3, param4)
{
	if(arguments.length == 4)
	{
		/* ... */
	}
	else
	{
		/* ... */
	}
}
</pre>
<h4>Parámetros indeterminados</h4>
<p>¿Como actuar si queremos que nuestra función tenga una cantidad indeterminada de parámetros? Normalmente, ante estos se pasan arrays como argumento, <em>arguments</em> nos soluciona el problema. Supongamos que nuestra función recibe un primer parámetro fijo, y el resto puede ser variable:</p>
<pre class="brush:js">
/* La invocación a la función */
mi_funcion(fijo, variable1, variable2, variable3, variable4, variable5);

/* La especificación de la función */
function mi_funcion(fijo)
{
	var variables = new Array();

	if(arguments.length > 1)
	{
		variables = arguments.slice(1);
	}

	/* ... */
}
</pre>
<p>De esta forma, el valor de el array <em>variables</em> será:</p>
<pre class="brush:js">
[
	variable1
	, variable2
	, variable3
	, variable4
	, variable5
]
</pre>
<h3>Conclusión</h3>
<p>El array arguments nos permite llevar un control de los argumentos que se pasan a las funciones, de forma que se puedan detectar las irregularidades que nosotros queramos y podamos actuar en consecuencia. Lo que hemos visto aquí es sólo una pequeña parte de las posiblidades que nos da arguments, y obviamente su uso dependerá de las necesidades de nuestra función, pero creo que es lo suficientemente ilustrativo como para conocer su potencial.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/02/09/el-array-arguments-de-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Clase para acceso avanzado a las AppSettings del WebConfig</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/02/08/clase-para-acceso-avanzado-a-las-appsettings-del-webconfig/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/02/08/clase-para-acceso-avanzado-a-las-appsettings-del-webconfig/#comments</comments>
		<pubDate>Mon, 08 Feb 2010 17:41:54 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[appsettings]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[webconfig]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=292</guid>
		<description><![CDATA[Para quien no lo sepa, el WebConfig de asp.Net es un archivo XML que contiene todos los aspectos de configuración de nuestra aplicación. Entre los distintos parámetros, hay un nodo llamado AppSettings que nos permite definir pares clave / valor para después acceder a ellas desde cualquier punto de la aplicación.

Pero, a pesar de que el api proporciona dos métodos diferentes de acceso a las AppSettings, ambos tienen algunos inconvenientes. Lo que haremos, es crear una pequeña clase que nos permitirá tratar las AppSettings de una forma más simple y con una funcionalidad mejorada.]]></description>
			<content:encoded><![CDATA[<p>Para quien no lo sepa, el WebConfig de asp.Net es un archivo XML que contiene todos los aspectos de configuración de nuestra aplicación. Entre los distintos parámetros, hay un nodo llamado AppSettings que nos permite definir pares clave / valor para después acceder a ellas desde cualquier punto de la aplicación.</p>
<p>Pero, a pesar de que el api proporciona dos métodos diferentes de acceso a las AppSettings, ambos tienen algunos inconvenientes. Lo que haremos, es crear una pequeña clase que nos permitirá tratar las AppSettings de una forma más simple y con una funcionalidad mejorada.<br />
<span id="more-292"></span></p>
<p><a href='http://www.juanmasantoyo.es/wp-content/uploads/2010/02/AppSettings.zip'>Clase AppSettings</a></p>
<h3>Los inconvenientes</h3>
<p>Los inconvenientes a la hora de trabajar con las variables de AppSettings son varios. Se podría decir que hay dos formas de acceder. Comentemos las dos formas:</p>
<h4>Primera forma: la clase ConfigurationManager</h4>
<p>La clase ConfigurationManager nos proporciona un diccionario estático que contiene los valores definidos en AppSettings:</p>
<pre class="brush:c-sharp">
ConfigurationManager.AppSettings["clave"];
</pre>
<p>A mi modo de ver, más largo de lo necesario y poco intuitivo (escribid &#8220;Configuration&#8221; en un VisualStudio y mirad cuantas entradas muestra el intellisense). Prometo que me costó un par de intentos memorizar esta línea.</p>
<p>Por otra parte, lo más grave es que el dato devuelto es siempre un <em>string</em>, lo cual nos obliga a hacer una conversión del dato inmediatamente después si queremos otro formato.</p>
<h4>Segunda forma: la clase AppSettingsReader</h4>
<p>Esta segunda clase, tiene algunas ventajas respecto a la anterior, pero también es mejorable.</p>
<p>Por una parte, su uso requiere de una instancia de AppSettingsReader y la posterior invocación a un método:</p>
<pre class="brush:c-sharp">
AppSettingsReader settings = new AppSettingsReader();
string valor = (string) settings.GetValue("clave", typeof(string));
</pre>
<p>Por no mencionar el casting obligatorio.</p>
<p>Por otra parte, aunque en principio se puede especificar el tipo del dato devuelto, hay poco control sobre él. ¿Qué pasa si es una fecha? Sinceramente, ni lo he probado.</p>
<h3>Una posible solución</h3>
<p>Yendo al grano, lo cierto es que el acceso a las AppSettings es mejorable. Vamos a considerar y a anotar algunas cosas sobre una posible alternativa que nos solucione los inconvenientes comentados:</p>
<ul>
<li>Se accede desde una clase estática, pero más simple que la vista en la primera forma de acceder. No debería ser mucho más complejo que <em>AppSettings.GetValue(&#8220;clave&#8221;)</em>.</li>
<li>Se ofrecen varios tipos básicos (pocos, pero controlados) como posibles retornos. Nuestra clase se encarga de hacer la conversión.</li>
<li>Además, la clase será capaz de realizar un tratamiento avanzado del contenido de las AppSettings: podrá retornar listas y diccionarios de los tipos básicos.</li>
</ul>
<h3>Definimos los diferentes tipos básicos de AppSettings</h3>
<p>Serán solamente cuatro, pero a cambio ganaremos el control absoluto sobre los valores que retornamos.</p>
<p>Los tipos serán:</p>
<ul>
<li><em>string</em></li>
<li><em>int</em></li>
<li><em>bool</em></li>
<li><em>DateTime</em></li>
</ul>
<h3>Definimos los diferentes formatos de las claves del AppSettings</h3>
<p>Vamos a estipular como deberán ser escritos los datos en el WebConfig. A partir de ahora, deberemos escribir los valores en AppSettings siguiendo uno de los formatos siguientes. aunque ante cualquier excepción, siempre podremos obtener los datos como un tipo básico <em>string</em> (que será como si no aplicásemos ninguna conversión). </p>
<h4>Datos básicos</h4>
<p>No consideraremos un formato para los datos básicos porque no lo necesitan (excepto las fechas, que las vemos ahora mismo). Las cadenas se escribirán como cadenas, los números como números, y los booleanos como <em>&#8220;true&#8221;</em> y <em>&#8220;false&#8221;</em>.</p>
<h4>Fechas</h4>
<p>Las fechas seguirán un formato típicamente español:</p>
<p>dia/mes/año</p>
<p>Donde los días van del 1 al 31, los meses del 1 al 12, y los años tienen cuatro cifras.</p>
<h4>Listas</h4>
<p>Separaremos los diferentes elementos con comas.</p>
<p>valor1, valor2, valor3, valor4</p>
<p>Los espacios en blanco entre los valores y las comas serán indiferentes.</p>
<h4>Diccionarios</h4>
<p> Separaremos los pares con comas, y los clave valor con dos puntos.</p>
<p>clave1: valor1, clave2: valor2, clave3: valor3</p>
<p>Al igual que antes, los espacios en blanco entre los separadores y los valores son indiferentes.</p>
<h3>Programamos la clase AppSettings</h3>
<p>Ya sabemos que formatos tenemos que considerar. Ahora vamos a programar nuestra clase.</p>
<p>Antes que nada, debemos tener más o menos claro cómo queremos hacerlo. Lo haremos así:</p>
<ul>
<li>Tendremos un método privado, llamado <em>Get</em>; que se encargará simplemente de obtener el dato de WebConfig como un <em>string</em>.</li>
<li>Tendremos tres métodos privados que se encargarán de convertir un <em>string</em> al resto de formatos. Se llamarán <em>ToInt</em>, <em>ToBool</em> y <em>ToDate</em>.</li>
<li>Tendremos varios métodos públicos, cada uno devolverá un tipo de dato. Los métodos se llamarán <em>GetAsString</em>, <em>GetAsStringList</em>, <em>GetAsStringDict</em>, <em>GetAsInt</em>, etc.</li>
</ul>
<h4>El método Get</h4>
<pre class="brush:c-sharp">
private static string Get(string key)
{
	AppSettingsReader settings = new AppSettingsReader();            

	return (string) settings.GetValue(key, typeof(string));
}
</pre>
<p>En este método tenemos la única instancia de AppSettingsReader que vamos a usar. El resto de métodos de la clase se apoyarán en este para obtener la información del WebConfig.</p>
<h4>Los métodos conversores</h4>
<p>Serán tres. Uno convertirá un <em>string</em> a <em>int</em>, otro a <em>bool</em> y el último a <em>DateTime</em>.</p>
<pre class="brush:c-sharp">
private static int ToInt(string value)
{
	int v = 0;

	if (int.TryParse(value, out v))
	{
		return v;
	}

	return 0;
}

private static bool ToBool(string value)
{
	bool v = false;

	if (bool.TryParse(value, out v))
	{
		return v;
	}

	return false;
}

private static DateTime ToDateTime(string value)
{
	DateTime v = DateTime.Today;

	if (DateTime.TryParseExact(value, "dd/MM/yyyy", new CultureInfo("es-ES"), DateTimeStyles.None, out v))
	{
		return v;
	}

	else return new DateTime();
}
</pre>
<h4>Los métodos que retornarán los datos</h4>
<p>Estos métodos se apoyarán en los anteriores para obtener los valores, darles un formato de salida y devolverlos. Hay uno por tipo de dato y tipo de salida (normal, lista o diccionario).</p>
<p>Además, a los métodos que requieran de un separador (los que devuelven listas y diccionarios) les haremos una sobrecarga que permita indicar un separador distinto. De esta forma podremos reaccionar ante posibles conflictos entre nuestros separadores por defecto y los valores que contengan las AppSettings.</p>
<pre class="brush:c-sharp">
public static string GetAsString(string key)
{
	string value = Get(key);

	return value;
}

public static int GetAsInt(string key)
{
	string value = Get(key);

	return ToInt(value);
}

public static bool GetAsBool(string key)
{
	string value = Get(key);

	return ToBool(value);
}

public static DateTime GetAsDateTime(string key)
{
	string value = Get(key);

	return ToDateTime(value);
}

public static List&lt;string&gt; GetAsStringList(string key, char sep)
{
	string value = Get(key);
	List&lt;string&gt; list = new List&lt;string&gt;();

	foreach (string s in value.Split(new char[] { sep }))
	{
		list.Add(s.Trim());
	}

	return list;
}

public static List&lt;string&gt; GetAsStringList(string key)
{
	return GetAsStringList(key, '|');
}

public static List&lt;int&gt; GetAsIntList(string key, char sep)
{
	string value = Get(key);
	List&lt;int&gt; list = new List&lt;int&gt;();

	foreach (string s in value.Split(new char[] { sep }))
	{
		list.Add(ToInt(s.Trim()));
	}

	return list;
}

public static List&lt;int&gt; GetAsIntList(string key)
{
	return GetAsIntList(key, '|');
}

public static List&lt;bool&gt; GetAsBoolList(string key, char sep)
{
	string value = Get(key);
	List&lt;bool&gt; list = new List&lt;bool&gt;();

	foreach (string s in value.Split(new char[] { sep }))
	{
		list.Add(ToBool(s.Trim()));
	}

	return list;
}

public static List&lt;bool&gt; GetAsBoolList(string key)
{
	return GetAsBoolList(key, '|');
}

public static List&lt;DateTime&gt; GetAsDateTimeList(string key, char sep)
{
	string value = Get(key);
	List&lt;DateTime&gt; list = new List&lt;DateTime&gt;();

	foreach (string s in value.Split(new char[] { sep }))
	{
		list.Add(ToDateTime(s.Trim()));
	}

	return list;
}

public static List&lt;DateTime&gt; GetAsDateTimeList(string key)
{
	return GetAsDateTimeList(key, '|');
}

public static Dictionary&lt;string, string&gt; GetAsStringDict(string key, char itemSep, char valueSep)
{
	string raw = Get(key);
	Dictionary&lt;string, string&gt; dict = new Dictionary&lt;string, string&gt;();

	foreach(string i in raw.Split(itemSep))
	{
		string item = i.Trim();

		string[] value = item.Split(valueSep);
		value[0] = value[0].Trim();
		value[1] = value[1].Trim();

		if (!dict.ContainsKey(value[0]))
		{
			dict.Add(value[0], value[1]);
		}
	}

	return dict;
}

public static Dictionary&lt;string, string&gt; GetAsStringDict(string key)
{
	return GetAsStringDict(key, ';', '|');
}

public static Dictionary&lt;string, int&gt; GetAsIntDict(string key, char itemSep, char valueSep)
{
	string raw = Get(key);
	Dictionary&lt;string, int&gt; dict = new Dictionary&lt;string, int&gt;();

	foreach (string i in raw.Split(itemSep))
	{
		string item = i.Trim();

		string[] value = item.Split(valueSep);
		value[0] = value[0].Trim();
		value[1] = value[1].Trim();

		if (!dict.ContainsKey(value[0]))
		{
			dict.Add(value[0], ToInt(value[1]));
		}
	}

	return dict;
}

public static Dictionary&lt;string, int&gt; GetAsIntDict(string key)
{
	return GetAsIntDict(key, ';', '|');
}

public static Dictionary&lt;string, bool&gt; GetAsBoolDict(string key, char itemSep, char valueSep)
{
	string raw = Get(key);
	Dictionary&lt;string, bool&gt; dict = new Dictionary&lt;string, bool&gt;();

	foreach (string i in raw.Split(itemSep))
	{
		string item = i.Trim();

		string[] value = item.Split(valueSep);
		value[0] = value[0].Trim();
		value[1] = value[1].Trim();

		if (!dict.ContainsKey(value[0]))
		{
			dict.Add(value[0], ToBool(value[1]));
		}
	}

	return dict;
}

public static Dictionary&lt;string, bool&gt; GetAsBoolDict(string key)
{
	return GetAsBoolDict(key, ';', '|');
}

public static Dictionary&lt;string, DateTime&gt; GetAsDateTimeDict(string key, char itemSep, char valueSep)
{
	string raw = Get(key);
	Dictionary&lt;string, DateTime&gt; dict = new Dictionary&lt;string, DateTime&gt;();

	foreach (string i in raw.Split(itemSep))
	{
		string item = i.Trim();

		string[] value = item.Split(valueSep);
		value[0] = value[0].Trim();
		value[1] = value[1].Trim();

		if (!dict.ContainsKey(value[0]))
		{
			dict.Add(value[0], ToDateTime(value[1]));
		}
	}

	return dict;
}

public static Dictionary&lt;string, DateTime&gt; GetAsDateTimeDict(string key)
{
	return GetAsDateTimeDict(key, ';', '|');
}
</pre>
<h3>¡Hemos terminado!</h3>
<p>Ahora ya tenemos una clase que, además de ser fácilmente utilizable desde cualquier parte del programa, nos proporciona los valores de AppSettings en el formato que necesitemos. Además hemos extendido la funcionalidad respecto al api de asp.Net por que también es capaz de obtener los datos en forma de listas y diccionarios.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/02/08/clase-para-acceso-avanzado-a-las-appsettings-del-webconfig/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Manual básico de Ajax (Parte 2)</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/02/05/manual-basico-de-ajax-parte-2/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/02/05/manual-basico-de-ajax-parte-2/#comments</comments>
		<pubDate>Fri, 05 Feb 2010 13:50:26 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[ajax]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[xmlhttprequest]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=247</guid>
		<description><![CDATA[Bueno, la teoría es necesaria pero lo bonito, y lo que a todos nos gusta es pringarnos las manos. Vamos allá con un ejemplo simple de Ajax.]]></description>
			<content:encoded><![CDATA[<h3>¡Pasemos a la acción!</h3>
<p>Bueno, la teoría es necesaria pero lo bonito, y lo que a todos nos gusta es pringarnos las manos. Vamos allá con un ejemplo simple de Ajax.<br />
<span id="more-247"></span><br />
El ejemplo consistirá en programar dos select. En el primero, tendremos una lista de países, y en el segundo una lista de ciudades. Lo que haremos, será modificar el select de ciudades en función del país seleccionado en el select de países.</p>
<p>El ejemplo tendrá tres partes: primero, programaremos la página HTML que contendrá los dos selects. Después programaremos un script de servidor en PHP, que será la petición Ajax y que generará la respuesta que contendrá toda la información sobre ciudades. Por último, programaremos un archivo JS que realizará la petición Ajax y que hará todas las gestiones pertinentes con el fin de presentar los resultados dentro del select de ciudades.</p>
<h4>El código fuente</h4>
<p>Este es el código fuente para este ejemplo. Te recomiendo que vayas mirando los archivos mientas los voy comentando:</p>
<p><a href='http://www.juanmasantoyo.es/wp-content/uploads/2010/02/nociones-basicas-de-ajax-src.zip'>Nociones básicas de Ajax (código fuente)</a>.</p>
<h4>La página HTML</h4>
<p>No nos complicaremos. Cumpliremos los requisitos básicos para generar un XHTML válido y fácil de maquetar con CSS; y que conste que es por orgullo propio, porque realmente al Ajax le va a dar igual si nuestro HTML valida o no.</p>
<p>En resumen, dos campos select y poco más.</p>
<h4>El Script PHP.</h4>
<p>En este caso, vamos a hacerlo fácil: guardaremos en arrays información sobre países y ciudades; y el script se limitará a recibir el país por GET y montar una salida XML que contenga los resultados.</p>
<p>Destacar que lo mismo que yo uso arrays, se podría hacer, por ejemplo; un acceso a base de datos. Y, obviamente, se podría usar cualquier otro lenguaje de servidor para generar el XML, como jsp o asp.</p>
<p>El XML generado será más o menos algo como esto:</p>
<pre class="brush:xml">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;pais codigo="1" nombre="España"&gt;
	&lt;ciudad codigo="101"&gt;Madrid&lt;/ciudad&gt;
	&lt;ciudad codigo="102"&gt;Barcelona&lt;/ciudad&gt;
	&lt;ciudad codigo="103"&gt;Palma de Mallorca&lt;/ciudad&gt;
	&lt;ciudad codigo="104"&gt;Sevilla&lt;/ciudad&gt;
	&lt;ciudad codigo="105"&gt;Valencia&lt;/ciudad&gt;
	&lt;ciudad codigo="106"&gt;Bilbao&lt;/ciudad&gt;
&lt;/pais&gt;</pre>
<p>Destacar dos cosas: los códigos de las ciudades se han generado mediante una sencilla fórmula:<br />
(código de la ciudad) = ((índice del país) * 100) + (índice de la ciudad)</p>
<p>Por otra parte, el código XML se ha montado en una línea única. Esto se hace así para no tener que lidiar con los saltos de línea cuando analicemos el XML con JavaScript (cada navegador los interpreta a su manera).</p>
<h4>El script JavaScript</h4>
<p>Ahora viene lo bueno. Este script hará tres cosas: gestionará la petición Ajax a ciudades.php, procesará el objeto XML resultante, y mostrará el resultado en pantalla.</p>
<p>Esta es con toda seguridad la parte más compleja de la pequeña aplicación que estamos programando.</p>
<p>A partir de ahora, el código merece una digna explicación, por lo que comentaré una a una todas las funciones del archivo js.</p>
<p>Empecemos con dos funciones sencillas: dos escuchadores de eventos.</p>
<pre class="brush:js">function paginaCargada()
{
	var pais = document.getElementById("pais");
	var ciudad = document.getElementById("ciudad");

	pais.disabled = false;
	pais.value = 0;

	ciudad.disabled = false;
	ciudad.value = 0;
}

function paisCambiado(select)
{
	var ciudades = document.getElementById("ciudad");
	ciudades.disabled = true;

	_actualizarCiudades(select.value);
}</pre>
<p>El escuchador <em>paginaCargada</em>, responde al evento de body <em>onload</em> y simplemente inicia los selectores de país y ciudad. Esto es para que al refrescar con F5 no conserven el valor anterior, y por si alguno hubiese quedado desactivado (durante el ejemplo, se desactivaran mientras se realiza la petición Ajax).</p>
<p>El escuchador <em>paisCambiado</em> responde al evento <em>onchange</em> del select de países. El único parámetro que recibe es el propio select de países.</p>
<p>La función de <em>paisCambiado</em> es simple: por una parte, deshabilita el select de ciudades (ya que se están cargando sus nuevos valores) y por otra, inicia la petición Ajax mediante la función <em>_actualizarCiudades</em>.</p>
<p>La siguiente función cumple la labor más importante de todas: crear un nuevo objeto Ajax y retornarlo.</p>
<pre class="brush:js">function ajax()
{
	var httpRequest = null;

	if (window.XMLHttpRequest)
	{
		//El explorador implementa el interfaz de forma nativa
		httpRequest = new XMLHttpRequest();
	}
	else if (window.ActiveXObject)
	{
		//El explorador permite crear objetos ActiveX
		try
		{
			httpRequest = new ActiveXObject("MSXML2.XMLHTTP");
		}
		catch (e)
		{
			try
			{
				httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
			}
			catch (e)
			{

			}
		}
	}

	return httpRequest;
}</pre>
<p>Una de las perticularidades del objeto <em>XMLHTTPRequest</em> (o ajax) es que está implementado de forma distinta en cada navegador. Firefox y la mayoría, lo traen implementado junto al resto de funcionalidades JavaScript, pero Internet Explorer lo trae implementado como un control ActiveX. Esta función hace exactamente eso: hace una detección de las funcionalidades del navegador y actúa en consecuencia para obtener una instancia del objeto <em>XMLHTTPRequest</em> y retornarla. Esta es una función muy típica, que de hecho ni siquiera es mía… en realidad la he copiado de la wikipedia: <a href="http://es.wikipedia.org/wiki/XMLHttpRequest">XMLHttpRequest en Wikipedia</a>.</p>
<p>Este objeto será el que realice las peticiones asíncronas y el que nos permita obtener los resultados.</p>
<p>Y todas estas cosas se hacen en la siguiente función: <em>_actualizarCiudades</em>. Mención especial a dos detalles: por una parte, fijaos en que a esta función la acompaña una variable global <em>ajx</em>. Por otra, fijaos en que el nombre de esta función empieza con un underscore. En este script, las funciones que empiezan con underscore son “teóricamente” privadas, o dicho de otra forma; son funciones que en teoría no deberían ser usadas desde fuera del script.</p>
<pre class="brush:js">var ajx = null;
function _actualizarCiudades(pais)
{
	if(ajx != null &amp;&amp; ajx.readyState != 4 &amp;&amp; ajx.readyState != 0)
	{
		ajx.abort();
	}

	ajx = ajax();
	var url = "ciudades.php?pais=" + pais;

	ajx.open("GET", url);
	ajx.send();

	ajx.onreadystatechange = function()
	{
		if(ajx.readyState == 4 &amp;&amp; ajx.status == 200 &amp;&amp; ajx.responseXML != null)
		{
			_ciudadesCargadas(ajx.responseXML);
			ajx = null;
		}
	}
}</pre>
<p>Veamos, lo primero a comentar de esta función es el primer if, y la razón de que el objeto <em>XMLHTTPRequest</em> se defina sobre una variable global <em>ajx</em>.</p>
<p>La idea es que las peticiones Ajax puedan ser canceladas si se intenta enviar una petición mientras hay otra en curso. Para ello, se basa en el valor de la propiedad <em>readyState</em>. Si el objeto <em>ajx</em> tiene la propiedad <em>readyState</em> en valores distintos a 4 (finalizado) o 0 (sin iniciar); es que existe una petición en curso y debe abortarse antes de que se inicie una nueva. Creo que esto se entenderá mejor con un pequeño diagrama de flujo:</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/nociones-basicas-de-ajax-102.png"><img class="aligncenter size-full wp-image-258" title="Gestión de peticiones Ajax" src="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/nociones-basicas-de-ajax-102.png" alt="" width="320" height="370" /></a></p>
<p>Ahora que estamos seguros de que no hay ninguna petición en curso, creamos un nuevo objeto Ajax.</p>
<p>Y lo que toca ahora, es crear la petición al servidor propiamente dicha. Lo primero, montar la URL a la que se accederá. Fijaos en que en este momento, concatenamos las variables que enviaremos por GET. Si quisiéramos hacer un POST, enviaríamos las variables en el método <em>ajx.send</em> (lo veremos en breve).</p>
<p>Ahora que tenemos la URL, y sabemos cómo enviaremos la información; podemos inicializar dichos valores en el objeto Ajax. Para ello usamos el método <em>ajx.open</em>.</p>
<p>Ahora el objeto <em>XMLHTTPRequest</em> sabe todo lo necesario para realizar una petición: la dirección, los parámetros a enviar, y la forma de enviarlos. Sólo nos queda lanzarla, y lo hacemos con el método <em>ajx.send</em>. Este método podría enviar también las variables POST en un objeto JavaScript. Algo como:</p>
<pre class="brush:js">ajx.send({
		var1 : “valor 1”
		, var2 : “valor2”
});</pre>
<p>Por último, necesitaremos controlar el estado de la petición para saber cuándo está lista, y actuar en consecuencia. Eso lo hacemos con un controlador de eventos, y el evento en cuestión es: <em>ajx.onreadystatechange</em>.</p>
<p>Este controlador se ejecutará cada vez que el valor de la propiedad <em>ajx.readyState</em> cambie, por lo que necesitaremos realizar una serie de validaciones antes de asumir que la petición ha finalizado:</p>
<p>Por una parte, necesitamos controlar que el valor de <em>ajx.readyState</em> sea 4 (que quiere decir que la petición ha finalizado), y por otra, necesitamos controlar que el valor de <em>ajx.status</em> sea 200 (este es el valor que retorna el servidor y que significa que no ha habido errores al servir la petición). No está de más comprobar que la propiedad <em>ajx.responseXML</em> contenga algún valor, ya que es donde esperamos encontrar el resultado.</p>
<p>Y ahora que sabemos que nuestra petición ha finalizado de forma satisfactoria, debemos analizar el resultado. Esto lo hará la función <em>_ciudadesCargadas</em>.</p>
<pre class="brush:js">function _ciudadesCargadas(xml)
{
	var ciudad = document.getElementById("ciudad");	

	var ciudadesDat = _parseaCiudades(xml);

	_actualizarSelectCiudades(ciudad, ciudadesDat);

	ciudad.disabled = false;
}</pre>
<p>Y el funcionamiento de esta función es muy simple. Se limita a hacer dos cosas: por una parte, procesa el resultado en la propiedad <em>ajx.responseXML</em> mediante la función <em>_parseaCiudades</em> y obtiene toda la información del xml en un objeto de JavaScript (bastante más manejable que el objeto XML que obtenemos del <em>ajx</em>), y por otra parte, envía el objeto al método <em>_actualizarSelectCiudades</em>, que se encarga de modificar el select de ciudades con los nuevos valores.</p>
<p>Además, una vez que todo el proceso ha terminado; esta función activará el select de ciudad (que se desactivó al lanzar la petición).</p>
<p>Esta sería la función que parsea el XML:</p>
<pre class="brush:js">function _parseaCiudades(xml)
{
	var data = {
		pais: null
		, ciudades: []
	};

	var pais = {
		codigo: null
		, nombre: null
	};

	var mainNode = null;

	//buscamos el nodo principal. no podemos asegurar su posición en el objeto xml por razones de crossbrowsing.
	for(var i = 0; i &lt; xml.childNodes.length; i++)
	{
		var node = xml.childNodes[i];
		if (node.nodeName == "pais")
		{
			mainNode = node;
			break;
		}
	}

	//rellenamos la estructura pais y lo añadimos a la estructura data.
	pais.codigo = mainNode.getAttribute("codigo");
	pais.nombre = mainNode.getAttribute("nombre");

	data.pais = pais;

	var ciudades = new Array();
	//creamos un array de estructuras ciudad y lo añadimos a la estructura data.
	for(var i = 0; i &lt; mainNode.childNodes.length; i++)
	{
		var node = mainNode.childNodes[i];

		if(node.nodeName == "ciudad")
		{
			ciudades[ciudades.length] = {
				codigo: node.getAttribute("codigo")
				, nombre: node.firstChild.nodeValue
			};
		}
	}

	data.ciudades = ciudades;

	return data;
}</pre>
<p>Lo cierto es que él código que encontramos en esta función merece un tutorial aparte. Os invito a que consideréis el código por vuestra cuenta porque de hecho no es demasiado complejo.</p>
<p>Sólo destacar un par de detalles: el objeto <em>mainNode</em> es el nodo principal del XML. En nuestro caso sería el nodo <em><br />
</em>, y por razones de crosbrowsing tenemos que hacer una búsqueda para encontrarlo (es decir, no podemos asumir que lo encontraremos en una posición determinada).</p>
<p>Por otra parte, notar que lo que hace el objeto en realidad es montar un objeto JavaScript con toda la información y retornarlo. Un objeto más o menos así:</p>
<pre class="brush:js">data = {
	país : {
		codigo : ""
		, nombre : ""
	}
	, ciudades : [
		{
            codigo : ""
			, nombre : ""
		}
		, {
            codigo : ""
			, nombre : ""
		}
		, …
	]
}</pre>
<p>Y este objeto llegará a la función <em>_actualizarSelectCiudades</em>, que cambiará la información que contiene el select de ciudades:</p>
<pre class="brush:js">function _actualizarSelectCiudades(ciudad, data)
{
	var isIe = '\v' == 'v'; //true si estamos en internet explorer

	//vaciamos el option
	var i = 0;
	while(ciudad.options.length &gt; 0)
	{
		ciudad.options[0] = null;
	}

	//añadimos los nuevos elementos
	for(var i = 0; i &lt; data.ciudades.length; i++)
	{
		var el = document.createElement("option");
		el.value = data.ciudades[i].codigo;
		el.text = data.ciudades[i].nombre;

		if(!isIe)
		{
			ciudad.add(el, null);
		}
		else
		{
			ciudad.add(el);
		}
	}
}</pre>
<p>Lo que se hace en esta función, es HTML Dom puro y duro. Es decir, modificar los elementos HTML mediante JavaScript. Primero vacía todo lo que hay en el select, y después añade los nuevos valores. Fijaos en la variable isIe: Detecta la funcionalidad del navegador para saber si estamos en Internet Explorer. Necesitamos saberlo por motivos de crossbrowsing, ya que los option se añaden de forma diferente en Internet Explorer y en el resto de navegadores.</p>
<h4>¡Hemos terminado!</h4>
<p>Después de este ejemplo, ya deberíamos tener más o menos claro como funciona una aplicación basada en Ajax. Hay que tener en cuenta que esto se puede complicar o simplificar tanto como uno quiera. Nuestro ejemplo ha sido muy sencillo, pero Ajax tiene mucha más potencia que esto si se usa bien.</p>
<p>Por otra parte, frameworks como <a href="http://jquery.com/">JQuery</a> o <a href="http://mootools.net/">Mootools</a> pueden llegar a simplificar muchísimo el trabajo con Ajax. Si realmente te interesa programar basado en Ajax, es obligatorio que les dediques unos minutos.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/02/05/manual-basico-de-ajax-parte-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Manual básico de Ajax (Parte 1)</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/02/05/nociones-basicas-de-ajax-parte-1/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/02/05/nociones-basicas-de-ajax-parte-1/#comments</comments>
		<pubDate>Fri, 05 Feb 2010 13:49:55 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[ajax]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=235</guid>
		<description><![CDATA[Aún hoy en día, varios años después de la salida de Gmail o google maps y la consiguiente popularización de Ajax, muchos desarrolladores no tienen claro de qué va esto y cómo funciona. 

En este artículo pretendo aclarar todo lo que se necesita saber para empezar a hacer pequeñas cosas con Ajax, y aportar una base para poder ampliar conocimientos sobre el tema con la idea de poder afrontar aplicaciones basadas en Ajax más complejas.

Inicialmente, este artículo iba a publicarse completo, pero como es algo extenso, lo dividiré en dos partes: primero, entenderemos qué es Ajax y cómo funciona. En la segunda parte, programaremos un sencillo ejemplo basado en Ajax.

Conviene avisar de que para poder entender algo de lo que se comenta en este artículo, se deben tener conocimientos medios de Java Script y PHP, y conocimientos básicos de HTML.]]></description>
			<content:encoded><![CDATA[<p>Aún hoy en día, varios años después de la salida de Gmail o google maps y la consiguiente popularización de Ajax, muchos desarrolladores no tienen claro de qué va esto y cómo funciona. </p>
<p>En este artículo pretendo aclarar todo lo que se necesita saber para empezar a hacer pequeñas cosas con Ajax, y aportar una base para poder ampliar conocimientos sobre el tema con la idea de poder afrontar aplicaciones basadas en Ajax más complejas.</p>
<p>Inicialmente, este artículo iba a publicarse completo, pero como es algo extenso, lo dividiré en dos partes: primero, entenderemos qué es Ajax y cómo funciona. En la segunda parte, programaremos un sencillo ejemplo basado en Ajax.</p>
<p>Conviene avisar de que para poder entender algo de lo que se comenta en este artículo, se deben tener conocimientos medios de Java Script y PHP, y conocimientos básicos de HTML.<br />
<span id="more-235"></span></p>
<h3>¿Qué es Ajax?</h3>
<p>La mejor forma de comprender qué es Ajax, es averiguar de dónde salen las siglas A.J.A.X.</p>
<p>Ajax significa “Asynchronous Java script And XML”. O en nuestra lengua: “Java script asíncrono y XML”.</p>
<p>De toda la definición, quizás lo más importante sea el concepto “asíncrono”, porque es la clave de todo: al fin y al cabo, lo que nos va a permitir el objeto Ajax es realizar una petición http asíncrona al servidor y procesar su resultado.</p>
<p>Que sea una petición http asíncrona, quiere decir que todo ocurrirá en segundo plano, sin que el usuario se dé cuenta de lo que está pasando.</p>
<p>Típicamente, la petición al servidor generará un resultado XML, aunque no tiene por qué (de ahí que XML se incluya en la definición de Ajax). Y no sólo eso, si no que dicho resultado vendrá en forma de objeto DOM y será fácilmente procesado mediante JavaScript.</p>
<p>Sin embargo, el resultado de una petición Ajax también puede obtenerse como texto plano o como HTML.</p>
<p>Resumiendo, Ajax:</p>
<ul>
<li>Es un objeto JavaScript que aportará el propio navegador.</li>
<li>Permitirá realizar peticiones asíncronas al servidor.</li>
<li>Aportará un resultado procesado como XML, HTML o, simplemente, un texto plano.</li>
</ul>
<h3>Un poco de arquitectura Web básica</h3>
<p>No podemos entender cómo trabaja Ajax, o cómo programar con Ajax; si no tenemos una idea clara de cómo es la arquitectura web básica.</p>
<p>Ajax trabaja como intermediario entre el cliente y el servidor, de ahí que es importante saber de forma básica cómo actúan ambos al realizar una petición http.</p>
<p>Antes que nada, el cliente (que supondremos que es un navegador) realiza una petición al servidor. Básicamente, solicitará un archivo.</p>
<p>El servidor escucha la petición y la resuelve. Esto, puede implicar muchas cosas. Puede ser simplemente localizar un archivo .html y enviarlo al cliente, o puede ser localizar un archivo .php, interpretarlo, acceder a base de datos, etc; para luego generar un nuevo código .html y enviarlo al cliente. Ésta es la parte más importante de nuestra aplicación web, ya que la parte de la aplicación que trabaja en el servidor será la única que no estará limitada por las funcionalidades del cliente. Por ejemplo, no podríamos acceder a base de datos con una tecnología de navegador como JavaScript.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/nociones-basicas-de-ajax-101.png"><img src="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/nociones-basicas-de-ajax-101.png" alt="" title="Arquitectura Cliente - Servidor" width="370" height="95" class="aligncenter size-full wp-image-240" /></a></p>
<p>Por lo tanto, hay cosas que nuestra aplicación sólo puede hacer en el lado del servidor. Y para obtener un resultado del servidor, necesitamos generar una nueva petición desde el navegador. Hablando en términos más sencillos: necesitamos recargar la página.</p>
<p>En este punto es donde entra en juego Ajax. Con Ajax, podremos generar esa petición en segundo plano. A base de JavaScript, podemos lanzar la petición, esperar el resultado del servidor, y mostrarlo en pantalla sin que nada de esto interrumpa la ejecución de la aplicación principal.</p>
<h3>Algunos ejemplos</h3>
<p>Para entender bien qué implica la posibilidad de realizar una petición al servidor en segundo plano, veamos algunos ejemplos.</p>
<h4>Caso Gmail</h4>
<p>Cuando Google lanzó Gmail, los servicios de Web mail estaban muertos. Nadie confiaba en ellos y siempre era preferible usar un cliente de correo de escritorio. Lo que hace de Gmail un cliente de Web mail tan especial, es que precisamente funciona exactamente igual que un cliente de correo de escritorio; esto se debe a que Gmail fue la primera aplicación web basada en Ajax.</p>
<p>Todo se basa en un detalle: Gmail es capaz de revisar periódicamente los correos entrantes, y mostrar los nuevos resultados en pantalla sin que ello implique un refresco de página. De forma que el usuario puede ver cómo llegan nuevos correos mientras está redactando uno, o mientras está leyendo. Dicho en otras palabras: Gmail es capaz de notificar la existencia de nuevos correos mediante peticiones al servidor que se realizan en segundo plano.</p>
<h4>Caso Google Maps</h4>
<p>No hay duda de que Google Maps es una de las aplicaciones más espectaculares de los últimos años. Y sin embargo, su funcionamiento es realmente simple. Sin Ajax, un Google Maps no sería posible, o al menos no sin Flash o otras tecnologías externas al navegador.</p>
<p>En realidad, Google Maps simplemente se dedica a analizar en qué posición del mapamundi estamos y que zoom estamos usando. Una vez concretados estos parámetros, se lanza una petición al servidor mediante Ajax, y el servidor notificará al cliente qué imágenes debe cargar, y en qué posición del mapa debe colocarlas. Sobra decir que sólo cargamos las imágenes del mapamundi que se están viendo en ese momento en la pantalla.</p>
<p>Por lo tanto, una vez más vuelve a ocurrir: se han obtenido resultados calculados por el servidor sin que ello haya implicado un refresco de página.</p>
<h3>Es todo por hoy</h3>
<p>Ahora ya sabemos lo básico de Ajax: sabemos cómo funciona y para qué sirve. En la segunda parte de este artículo, veremos un ejemplo que nos ayudará a comprender mejor cómo funciona la programación basada en Ajax.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/02/05/nociones-basicas-de-ajax-parte-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Barra estilo facebook con CSS</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/02/05/barra-estilo-facebook-con-css/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/02/05/barra-estilo-facebook-con-css/#comments</comments>
		<pubDate>Fri, 05 Feb 2010 10:24:51 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[css]]></category>
		<category><![CDATA[css position fixed]]></category>
		<category><![CDATA[facebook]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=185</guid>
		<description><![CDATA[Hoy he entrado en facebook y me he llevado una sorpresa y una decepción. La sorpresa era que me han aplicado el nuevo diseño, ahora parece aún más simple. La decepción era que el nuevo diseño implicaba la desaparición de la barra inferior. Esa barra que tantos tutoriales ha inspirado, esa barra que parecía inmune al scroll del ratón. De ella sólo queda ya una sombra de lo que fue, una pequeña caja de chat en la esquina inferior derecha.
En homenaje a ella, hoy comentaré cómo podemos hacer nosotros la nuestra.]]></description>
			<content:encoded><![CDATA[<p>Hoy he entrado en facebook y me he llevado una sorpresa y una decepción. La sorpresa era que me han aplicado el nuevo diseño, ahora parece aún más simple. La decepción era que el nuevo diseño implicaba la desaparición de la barra inferior. Esa barra que tantos tutoriales ha inspirado, esa barra que parecía inmune al scroll del ratón. De ella sólo queda ya una sombra de lo que fue, una pequeña caja de chat en la esquina inferior derecha.</p>
<p>En homenaje a ella, hoy comentaré cómo podemos hacer nosotros la nuestra (<a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/facebookBar.html">demo</a>).<br />
<span id="more-185"></span></p>
<h3>Conociendo el problema</h3>
<p>La técnica que se usa para este tipo de posicionamiento, no es JavaScript como muchos pueden pensar; eso es de principios de la década pasada. Con CSS2 llegaron <a href="http://www.w3schools.com/css/pr_class_position.asp">nuevos tipos de posicionamiento</a> para los elementos que nos permitirán crear el efecto.</p>
<p>El posicionamiento que a nosotros nos ocupa es &#8220;position: fixed&#8221;. Este tipo de posicionamiento coloca el elemento respecto a la ventana del navegador, y podemos especificar las coordenadas con las propiedades &#8220;top&#8221;, &#8220;right&#8221;, &#8220;bottom&#8221; y &#8220;left&#8221;.</p>
<h3>Programamos la barra</h3>
<p>Lo que haremos será aplicar estilos CSS a una capa con el id “facebookBar”. Esta clase determinará el posicionamiento a la capa, además de otros aspectos gráficos como color, borde, etc.</p>
<h4>Una página para probar</h4>
<p>Para que el efecto se aprecie bien, vamos a crear una página con bastante contenido y que nos permita hacer scroll.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/facebookBar.html">facebookBar.html</a></p>
<p>Como veis, nada del otro mundo. La última capa en el archivo, es a la que se aplicará el efecto de posicionamiento. Sólo destacar el Doctype. Es muy importante para que los navegadores apliquen correctamente los CSS.</p>
<pre class="brush:xml">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"&gt;
</pre>
<h4>El CSS</h4>
<p>Os habréis fijado que en el HTML hay un link al CSS. Lo que contendrá ese archivo será un poco de maquetación básica para el contenido de la página, y un par de reglas CSS para aplicar el posicionamiento a la barra de facebook.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/02/facebookBar.css">facebookBar.css</a></p>
<p>Comentemos un poco el código.</p>
<p>La clase más importante, es #facebookBar:</p>
<pre class="brush:css">#facebookBar
{
	position: fixed; /* Posicionamiento */
	bottom: 0px;
	left: 20px;
	right: 20px;

	border: solid 1px #666666; /* Los bordes de la barra */
	border-bottom: none;

	background-color: #cccccc; /* Un color de fondo */

	height: 25px; /* Altura que tomará la barra. 25 (height) + 4 (padding) + 1 (borde superior) = 30 */
	padding: 2px;
}
</pre>
<p>Por una parte, está el código de posicionamiento. Como hemos comentado, tiene el position en fixed. También tiene bottom en 0px para que la capa quede pegada al borde inferior de la ventana, y left y right a 20px para dejar 20 píxeles de margen a cada lado.</p>
<p>Aparte de eso, poca cosa más. Un poco de bordes y de color de fondo para dejarla bonita.</p>
<p>Lo último que queda por comentar, es la clase #contenido. Es muy importante, porque hace un pequeño ajuste que evitará que nuestra barra de facebook pise parte del texto al llegar al final de la página.</p>
<pre class="brush:css">#contenido
{
	margin-bottom: 50px; /* Evitará que nos quede contenido oculto al llegar al final de la página */
}
</pre>
<p>El ajuste en cuestión consiste en añadir un margen inferior. Como la barra mide 30 píxeles de alto, y el margen es de 50 píxeles; al llegar al final de la página quedará una separación entre el contenido y la barra de 20 píxeles.</p>
<h3>¡Hemos acabado!</h3>
<p>Y con sólo estas dos clases CSS tenemos acabada nuestra barra de facebook. El position fixed colocará la capa por encima de cualquier elemento que no tenga un z-index superior, así que modificando las reglas top, right, bottom, left, width y height de #facebookBar podemos adaptarla para muchos tipos de usos. Te invito a que experimentes.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/02/05/barra-estilo-facebook-con-css/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>De nuevo activo</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/02/04/de-nuevo-activo/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/02/04/de-nuevo-activo/#comments</comments>
		<pubDate>Thu, 04 Feb 2010 21:45:20 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[general]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=182</guid>
		<description><![CDATA[Hoy, mientras arreglaba un poco el blog que estaba muy abandonado y desmantelado; me he dado cuenta de que hacía cerca de un año que no publicaba nada decente.

Llevaba mucho tiempo queriendo retomar el blog con un aire más profesional / académico, pero no encontraba el rato y las ganas de hacer la reforma que he hecho hoy.

Se ha limpiado casi el 90% del blog, y solo han sobrevivido las pocas entradas sobre desarrollo de software que tenía. Irónico si tenemos en cuenta que dedico el 90% de la jornada a desarrollar software.

Bueno, confío en que todo sea mucho mejor apartir de ahora. En breve un tutotial de Ajax con JavaScript nativo que tengo por ahí pendiente de publicación, y un manual de introducción al desarrollo para microsoft surface (que no verá la luz hasta que se haya publicado en otro lugar).]]></description>
			<content:encoded><![CDATA[<p>Hoy, mientras arreglaba un poco el blog que estaba muy abandonado y desmantelado; me he dado cuenta de que hacía cerca de un año que no publicaba nada decente.</p>
<p>Llevaba mucho tiempo queriendo retomar el blog con un aire más profesional / académico, pero no encontraba el rato y las ganas de hacer la reforma que he hecho hoy.</p>
<p>Se ha limpiado casi el 90% del blog, y solo han sobrevivido las pocas entradas sobre desarrollo de software que tenía. Irónico si tenemos en cuenta que dedico el 90% de la jornada a desarrollar software.</p>
<p>Bueno, confío en que todo sea mucho mejor apartir de ahora. En breve un tutotial de Ajax con JavaScript nativo que tengo por ahí pendiente de publicación, y un manual de introducción al desarrollo para microsoft surface (que no verá la luz hasta que se haya publicado en otro lugar).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/02/04/de-nuevo-activo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Olor de código</title>
		<link>http://www.juanmasantoyo.es/index.php/2008/12/05/olor-de-codigo/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2008/12/05/olor-de-codigo/#comments</comments>
		<pubDate>Fri, 05 Dec 2008 00:02:30 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[programación]]></category>
		<category><![CDATA[olor de codigo]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/index.php/2008/12/05/olor-de-codigo/</guid>
		<description><![CDATA[Los programadores solemos cometer dos errores:

El primero, pensar que con echar un simple vistazo a un código podemos determinar si es o no es un buen código.

El segundo, pensar que lo anterior es un error.

En realidad, la primera impresión de un código es bastante válida. Cuando un código no nos convence a primera vista, es por que despide un "olor" poco convincente. Lo que vengo a decir, es que esto del olor de código existe y <a href="http://en.wikipedia.org/wiki/Code_smell">está mas o menos documentado</a>. Sin embargo, no he encontrado nada en español sobre el tema, así que vamos allá.]]></description>
			<content:encoded><![CDATA[<p>Los programadores solemos cometer dos errores:</p>
<p>El primero, pensar que con echar un simple vistazo a un código podemos determinar si es o no es un buen código.</p>
<p>El segundo, pensar que lo anterior es un error.</p>
<p>En realidad, la primera impresión de un código es bastante válida. Cuando un código no nos convence a primera vista, es por que despide un &#8220;olor&#8221; poco convincente. Lo que vengo a decir, es que esto del olor de código existe y <a href="http://en.wikipedia.org/wiki/Code_smell">está mas o menos documentado</a>. Sin embargo, no he encontrado nada en español sobre el tema, así que vamos allá:<br />
<span id="more-81"></span><br />
¿Qué cosas provocan mal olor en nuestro código y como solucionarlas?</p>
<ul>
<li><strong>Código duplicado.</strong> A primera vista ya podemos ver trozos de código demasiado parecidos. Probablemente deberíamos encontrar una forma de compartir ese código para no repetirlo por todo nuestro programa.</li>
<li><strong>Métodos demasiado largos.</strong> Cuando un método es demasiado largo, lo más seguro es que debamos dividirlo en más métodos más básicos. Eso hará nuestro código más comprensible y más sencillo de arreglar cuando falle (porque creeme, fallará).</li>
<li><strong>Clases demasiado largas.</strong> Un poco en la misma linea que lo anterior, es posible que necesites abstraer un poco más tu código, y dividir una clase en varias clases pequeñas.</li>
<li><strong>Envidia de características.</strong> Lo mismo te digo una cosa que te digo otra. Si notamos que una de nuestras clases usa excesívamente los métodos de otra, merece la pena cosiderar si realmente esas dos clases deberían estar separadas.</li>
<li><strong>Intimidad inapropiada.</strong> Una clase no debería depender de otras clases en según que aspectos de implementación críticos. Las clases deberían ser reutilizables y independientes. En estas situaciones tambien deberíamos plantearnos la fusión de las dos clases.</li>
<li><strong>Rechazo del legado.</strong> Una clase que sobreescribe un método heredado debería respetar el propósito inicial del método. Con esto quiero decir que no es lógico ni aceptable que un método que calcule raízes cuadradas se sobreescriba con un método que elimine acentos en una cadena de texto. No tienen nada que ver el uno con el otro. La pregunta que deberíamos hacernos ahora es: ¿realmente esta clase debería tener este padre y no otro?. Recordemos que la composición siempre es una solución válida.</li>
<li><strong>Clases perezosas.</strong> Hemos hablado de clases demasiado largas, pero ¿y las clases demasiado cortas?. Puede que debamos integrar su funcionalidad en otra clase.</li>
<li><strong>Métodos duplicados.</strong> ¿Realmente necesitamos ese método para elevar al cubo teniendo este que eleva al cuadrado?. Mucho mejor si hacemos un método capaz de elevar a n. Debemos evitar tener varios métodos con funcionalidades parecidas y buscar más métodos configurables con parámetros.</li>
<li><strong>Complejidad artificial.</strong> ¿Estamos ante un problema complicado o nosotros lo hemos vuelto complicado?. No tiene sentido forzar, por ejemplo, el uso de complejos <a href="http://es.wikipedia.org/wiki/Patrones_de_dise%C3%B1o">patrones de diseño</a> en problemas que realmente son tan sencillos que no los requieren.</li>
</ul>
<p>Estas son algunas fuentes potenciales de problemas que podemos llegar a tener y que son fáciles de ver con un vistazo simple al código. El código puede, y debe; ser bonito.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2008/12/05/olor-de-codigo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google sitemaps, plugin para wordpress</title>
		<link>http://www.juanmasantoyo.es/index.php/2007/09/12/google-sitemaps-plugin-para-wordpress/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2007/09/12/google-sitemaps-plugin-para-wordpress/#comments</comments>
		<pubDate>Tue, 11 Sep 2007 22:21:38 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/index.php/2007/09/12/google-sitemaps-plugin-para-wordpress/</guid>
		<description><![CDATA[Hacía tiempo que quería comentar esto.  Los sitemaps son archivos XML con una sintaxis específica, que aporta una información a los buscadores que les es de mucha utilidad para indexar nuestro sitio. No importa decir que a los webmasters nos es de mucha utilidad que a los buscadores algo de nuestro sitio les resulte de utilidad. Vaya gilipollez xD.

Bueno, Google sitemaps es un sistema de sitemaps creado por Google para indexar sitios en dicho buscador.]]></description>
			<content:encoded><![CDATA[<p>Hacía tiempo que quería comentar esto.  Los sitemaps son archivos XML con una sintaxis específica, que aporta una información a los buscadores que les es de mucha utilidad para indexar nuestro sitio. No importa decir que a los webmasters nos es de mucha utilidad que a los buscadores algo de nuestro sitio les resulte de utilidad. Vaya gilipollez xD.</p>
<p>Bueno, Google sitemaps es un sistema de sitemaps creado por Google para indexar sitios en dicho buscador.<br />
<span id="more-48"></span><br />
Sobre sitemaps hay mucha información en la web, pero siempre algo incompleta. En estos asuntos de posicionamiento siempre hay cierto halo de misterio: el secretismo que guardan los buscadores con la intención de ser los mejores provoca que la gente especule mucho y nadie hable con seguridad sobre como posicionar una web.</p>
<p>En fin, lo que nos ocupa es este plugin para wordpress, que automatiza todo el mantenimiento del sitemap de tu blog.</p>
<p><a href="http://www.arnebrachhold.de/2005/06/05/google-sitemaps-generator-v2-final">http://www.arnebrachhold.de/2005/06/05/google-sitemaps-generator-v2-final</a></p>
<p>Fácil de instalar y de configurar, lo único que se le pide a un buen plugin. A mi inicialmente no me funcionaba, pero creo que el servidor tenial algún problema extraño. Sin venir a cuento ahora me ha empezado a ir bien&#8230; en fin, prefiero no preguntar, el servidor nunca ha ido demasiado fino&#8230; pero eso es otra historia xD.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2007/09/12/google-sitemaps-plugin-para-wordpress/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HeidiSQL</title>
		<link>http://www.juanmasantoyo.es/index.php/2007/07/16/heidisql/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2007/07/16/heidisql/#comments</comments>
		<pubDate>Mon, 16 Jul 2007 13:07:16 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/index.php/2007/07/16/heidisql/</guid>
		<description><![CDATA[Con este curioso nombre se me presenta hace un par de dias una aplicación de escritorio bastante interesante para trabajar sobre bases de datos. La historia es algo así:

Un programador que en ocasiones trabaja con nosotros, me habló de que él no suele usar phpMyAdmin para trabajar en las bases de datos, él usa mysql-front; que viene siendo lo mismo pero como aplicación de escritorio. Las ventajas de gestionar una base de datos desde una aplicación de escritorio en vez de desde la web es obvia. Ganas comodidad y velocidad. Así que me pongo a informarme sobre el programa.]]></description>
			<content:encoded><![CDATA[<p>Con este curioso nombre se me presenta hace un par de dias una aplicación de escritorio bastante interesante para trabajar sobre bases de datos. La historia es algo así:</p>
<p>Un programador que en ocasiones trabaja con nosotros, me habló de que él no suele usar phpMyAdmin para trabajar en las bases de datos, él usa mysql-front; que viene siendo lo mismo pero como aplicación de escritorio. Las ventajas de gestionar una base de datos desde una aplicación de escritorio en vez de desde la web es obvia. Ganas comodidad y velocidad. Así que me pongo a informarme sobre el programa.<br />
<span id="more-41"></span><br />
Lo primero que me llevo es una gran desilusión, parece ser que la aplicación es de pago. Nisiquiera me molesto en bajar el trial de 30 días. Claro, podria hacer algún truco, pero el problema no era ese, sinó que la verdad, me repugna bastante el software de pago, mi intención es llegar a prescindir de el.</p>
<p>Total, que pasa el tiempo y el otro dia me decido a buscar algo así de código abierto. Y cual es mi sorpresa al encontrarme con HeidiSQL, que no solo es un programa con la misma funcionalidad que mysql-front, sino que es el propio mysql-front antes de que este se hiciese de pago.  Parece ser que el autor lo vendió a quien fuese que lo hizo de pago y posteriormente liberó el código original bajo este nuevo nombre.</p>
<p>En fin, no he tenido tiempo de probarlo demasiado, pero parece que esta bastante bien. Quizas le falta un editor gráfico para la base de datos (algo que te permita construir la estructura en vista de diagrama), pero por lo demás tiene buena pinta.</p>
<p><a href="http://www.heidisql.com/">HeidiSQL</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2007/07/16/heidisql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
