<?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>Fri, 18 May 2012 06:06:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>JSFiffle, consola Javascript para agilizar tus desarrollos</title>
		<link>http://www.juanmasantoyo.es/index.php/2012/05/18/jsfiffle-consola-javascript-para-agilizar-tus-desarrollos/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2012/05/18/jsfiffle-consola-javascript-para-agilizar-tus-desarrollos/#comments</comments>
		<pubDate>Fri, 18 May 2012 06:06:08 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[general]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=798</guid>
		<description><![CDATA[Mi buen compañero Jaime Rosselló me hablaba hace un par de días de JSFiddle, una herramienta online que nos permitirá codificar nuestros Javascripts de forma mucho más productiva. Se trata de una consola sobre la cual podremos definir nuestro un &#8230; <a href="http://www.juanmasantoyo.es/index.php/2012/05/18/jsfiffle-consola-javascript-para-agilizar-tus-desarrollos/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Mi buen compañero Jaime Rosselló me hablaba hace un par de días de JSFiddle, una herramienta online que nos permitirá codificar nuestros Javascripts de forma mucho más productiva.</p>
<p>Se trata de una consola sobre la cual podremos definir nuestro un entorno HTML y CSS sencillo para poder empezar a codificar Javascript como locos.</p>
<p>Como no tengo tiempo, no me enrollo más. Espero que esta herramienta os sea de utilidad: <a title="JSFiddle" href="http://jsfiddle.net/">JSFiddle</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2012/05/18/jsfiffle-consola-javascript-para-agilizar-tus-desarrollos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>El objeto RegExp de JavaScript. Las dos cosas que van a cubrir la mayoría de tus necesidades.</title>
		<link>http://www.juanmasantoyo.es/index.php/2012/01/19/el-objeto-regexp-de-javascript-las-dos-cosas-que-van-a-cubrir-la-mayoria-de-tus-necesidades/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2012/01/19/el-objeto-regexp-de-javascript-las-dos-cosas-que-van-a-cubrir-la-mayoria-de-tus-necesidades/#comments</comments>
		<pubDate>Thu, 19 Jan 2012 06:31:42 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=783</guid>
		<description><![CDATA[Las expresiones regulares tienen muchos usos, pero la mayoría de las veces sólo vas a hacer dos cosas: Comprobar si una cadena cumple el patrón Extraer subcadenas de la cadena de origen Voy a ilustrar en un par de ejemplos &#8230; <a href="http://www.juanmasantoyo.es/index.php/2012/01/19/el-objeto-regexp-de-javascript-las-dos-cosas-que-van-a-cubrir-la-mayoria-de-tus-necesidades/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Las expresiones regulares tienen muchos usos, pero la mayoría de las veces sólo vas a hacer dos cosas:</p>
<ol>
<li>Comprobar si una cadena cumple el patrón</li>
<li>Extraer subcadenas de la cadena de origen</li>
</ol>
<p>Voy a ilustrar en un par de ejemplos cómo se usa el objeto RegExp de JavaScript, el cual nos permite usar expresiones regulares.</p>
<p><span id="more-783"></span></p>
<h3>Crear un objeto RegExp</h3>
<p>Veamos primero cómo se construye un objeto RegExp. Hay dos formas:</p>
<h4>Forma tradicional</h4>
<p>El RegExp se puede crear mediante un constructor, como cualquier otro objeto. Los argumentos del constructor son dos strings: el patrón y los modificadores. Un ejemplo:</p>
<pre class="brush:javascript">var expression = new RegExp('^.* prueba$', 'i');</pre>
<p>El modificador usado es el <em>case <strong>i</strong>nsensitive</em>.</p>
<p>La gran ventaja de este sistema es que el patrón se crea con un string, lo cual permite crear el patrón de forma dinámica.</p>
<h4>Forma simplificada</h4>
<p>Otra forma de crear un objeto RegExp es mediante una estructura del tipo: <em>/patrón/modificadores</em>. Por ejemplo:</p>
<pre class="brush:javascript">var expression = /^.* prueba$/i;</pre>
<h3>Comprobar si una cadena cumple el patrón</h3>
<p>La mayoría de las veces sólo queremos saber si una cadena cumple un patrón. Para ello, contamos con el método Test de RegExp, que devolerá <em>true</em> o <em>false</em> según se cumpla el patrón o no:</p>
<pre class="brush:javascript">var expression = /^.* prueba$/i;
var str = 'Esto es una prueba';
expression.test(str); // true</pre>
<h3>Extraer subcadenas de la cadena de origen</h3>
<p>Con las expresiones regulares también es posible extraer trozos de la cadena original. Para ello, se deben definir grupos en el patrón mediante el uso de paréntesis.</p>
<p>El método exec de RegExp nos retornará un array con todos los valores extraídos, y es nuestra responsabilidad saber qué índice del array ocupará el valor que buscamos. Hay que tener en cuenta que el índice 0 siempre será la cadena original.</p>
<pre class="brush:javascript">var expression = /^.* (.*)$/i;
var str = 'Esto es una prueba';
expression.exec(str); // ['Esto es una prueba', 'prueba']</pre>
<h3>Una mención especial al método Replace</h3>
<p>Con lo anterior ya he cubierto los usos más interesantes de RegExp, pero el método Replace del objeto String merece una mención especial, ya que se vuelve mucho más potente si lo usamos con objetos RegExp. Podéis consultarlo aquí: <a title="Método Replace" href="http://w3schools.com/jsref/jsref_obj_string.asp">Metodo Replace</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2012/01/19/el-objeto-regexp-de-javascript-las-dos-cosas-que-van-a-cubrir-la-mayoria-de-tus-necesidades/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Formatear cadenas con placeholders en JavaScript (II)</title>
		<link>http://www.juanmasantoyo.es/index.php/2012/01/16/formatear-cadenas-con-placeholders-en-javascript-ii/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2012/01/16/formatear-cadenas-con-placeholders-en-javascript-ii/#comments</comments>
		<pubDate>Mon, 16 Jan 2012 21:48:44 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=776</guid>
		<description><![CDATA[Esta mañana comentaba una función que estoy utilizando para construir cadenas con placeholders en JavaScript. Mientras acababa el post, consideré la opción de hacerle una pequeña mejora, pero no tenía tiempo. Así que publico ahora dicha mejora. La idea es &#8230; <a href="http://www.juanmasantoyo.es/index.php/2012/01/16/formatear-cadenas-con-placeholders-en-javascript-ii/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Esta mañana comentaba <a href="http://www.juanmasantoyo.es/index.php/2012/01/16/formatear-cadenas-con-placeholders-en-javascript/" title="Formatear cadenas con placeholders en JavaScript">una función</a> que estoy utilizando para construir cadenas con placeholders en JavaScript. Mientras acababa el post, consideré la opción de hacerle una pequeña mejora, pero no tenía tiempo. Así que publico ahora dicha mejora.<br />
<span id="more-776"></span><br />
La idea es poder usar la misma técnica sin la necesidad de que los placeholders sean identificadores numéricos. Es decir, un placeholder podría identificarse con una cadena de texto cualquiera. Por ejemplo, esto es lo que teníamos antes:</p>
<pre class="brush:javascript">var precioFinal = stringFormat('El precio final es de {0} {1}', precio, moneda);</pre>
<p>La idea es poder hacer algo como esto:</p>
<pre class="brush:javascript">
var precioFinal = stringFormat('El precio final es de {precio} {moneda}'
    , {
        'precio' : precio
        , 'moneda' : moneda
    }
);
</pre>
<p>Esto es mucho más simple de usar ya que nos elimina la complejidad de tener que conocer el identificador numérico de cada argumento que usamos, lo cual es fácil si tenemos pocos parámetros, pero se complica si usamos varios.</p>
<p>Ésta es la función:</p>
<pre class="brush:javascript">
function stringFormat(string, values)
{
    for(var i in values)
    {
        var expresion = new RegExp('\\{' + (i) + '\\}', 'ig');
        string = string.replace(expresion, values[i]);
    }

    return string;
}
</pre>
<p>En realidad, el algoritmo se basa en un <em>for in</em>, eso quiere decir que si queremos usar la función con placeholders numéricos también podríamos hacer algo como:</p>
<pre class="brush:javascript">
var precioFinal = stringFormat('El precio final es de {0} {1}'
    , [
        precio
        , moneda
    ]
);
</pre>
<p>¡Espero que esta función os sea de utilidad!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2012/01/16/formatear-cadenas-con-placeholders-en-javascript-ii/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Formatear cadenas con placeholders en JavaScript</title>
		<link>http://www.juanmasantoyo.es/index.php/2012/01/16/formatear-cadenas-con-placeholders-en-javascript/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2012/01/16/formatear-cadenas-con-placeholders-en-javascript/#comments</comments>
		<pubDate>Mon, 16 Jan 2012 10:38:04 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=766</guid>
		<description><![CDATA[Normalmente, intento evitar lo máximo posible la concatenación de valores en una cadena. Por ejemplo, no me gusta hacer cosas como esta: var precioFinal = 'El precio final es de ' + precio + ' ' + moneda; El motivo &#8230; <a href="http://www.juanmasantoyo.es/index.php/2012/01/16/formatear-cadenas-con-placeholders-en-javascript/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Normalmente, intento evitar lo máximo posible la concatenación de valores en una cadena. Por ejemplo, no me gusta hacer cosas como esta:</p>
<pre class="brush:javascript">var precioFinal = 'El precio final es de ' + precio + ' ' + moneda;</pre>
<p>El motivo es que con este tipo de estructura es fácil cometer un error. No soy muy bueno probando mi código, así que para compensar intento programar siempre de forma que sea difícil cometer errores.</p>
<p><span id="more-766"></span></p>
<p>Por lo tanto, cuando se trata de montar cadenas de texto en Java Script solía hacer algo como esto para imitar la funcionalidad String.Format de .Net:</p>
<pre class="brush:javascript">var precioFinal = 'El precio final es de {0} {1}'
     .replace('\{0\}', precio)
     .replace('\{1\}', moneda)</pre>
<p>Cuando lo hice dos veces me di cuenta de que necesitaba una función. Cuando lo hice veinte veces, hice la maldita función de una vez&#8230; ya sabéis cómo es esto.</p>
<p>La idea era simple: usar el array arguments de Javascript para implementar una especie de String.Format. Allá va:</p>
<pre class="brush:javascript">function stringFormat(string)
{
    if(arguments.length &gt; 1)
    {
        for(var i = 1; i &lt; arguments.length; i++)
        {
            var expresion = new RegExp('\\{' + (i - 1) + '\\}', 'ig');
            string = string.replace(expresion, arguments[i]);
        }
    }

    return string;
}</pre>
<p>La función es tan simple como parece. Tan solo busca los placeholders y los reemplaza por su valor correspondiente. Se usaría así:</p>
<pre class="brush:javascript">var precioFinal = stringFormat('El precio final es de {0} {1}', precio, moneda);</pre>
<p>Parece una tontería, pero sabiendo que la tengo en el blog ya no me volverá a dar pereza implementarla <img src='http://www.juanmasantoyo.es/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2012/01/16/formatear-cadenas-con-placeholders-en-javascript/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Felicidades Windows Phone. Algunos enlaces de interés.</title>
		<link>http://www.juanmasantoyo.es/index.php/2011/10/24/felicidades-windows-phone-algunos-enlaces-de-interes/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2011/10/24/felicidades-windows-phone-algunos-enlaces-de-interes/#comments</comments>
		<pubDate>Mon, 24 Oct 2011 18:43:55 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[windows phone]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=711</guid>
		<description><![CDATA[La semana pasada Windows Phone cumplió un añito y hay que celebrarlo. Me gustaría compartir algunos enlaces que ayudarán a los que aún no se han iniciado en esta tecnología, y que también nos serán útiles a los que ya &#8230; <a href="http://www.juanmasantoyo.es/index.php/2011/10/24/felicidades-windows-phone-algunos-enlaces-de-interes/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>La semana pasada Windows Phone cumplió un añito y hay que celebrarlo.</p>
<p>Me gustaría compartir algunos enlaces que ayudarán a los que aún no se han iniciado en esta tecnología, y que también nos serán útiles a los que ya hemos hecho algunas cositas.<br />
<span id="more-711"></span></p>
<h3>Instalación del entorno de desarrollo</h3>
<p>Nada más fácil, instalar el entorno de desarrollo es tan sencillo como <a title="Windows Phone SDK 7.1" href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;id=27570">descargar el instalador</a>.</p>
<h3>Cursos online</h3>
<p>Microsoft publicó no hace mucho un curso online muy decente, que incluso contempla algunas sesiones programadas de tutorías con gente que sabe de esto: <a title="Curso Online de Desarrollo de Aplicaciones en Silverlight para Windows Phone" href="http://msdn.microsoft.com/es-es/windowsphone/hh307892">Curso Online de Desarrollo de Aplicaciones en Silverlight para Windows Phone</a>.</p>
<p>Tampoco podemos olvidar esa gran fuente de sabiduría que es msdn: <a title="Windows Phone Development" href="http://msdn.microsoft.com/library/ff402535%28v=VS.92%29.aspx">Windows Phone Development</a>.</p>
<h3>Ejemplos</h3>
<p>Por último, siempre viene bien tener a mano una buena fuente de ejemplos. Me gusta mucho la que compartían hoy mismo los chicos de <a title="Speaking in .NET" href="http://speakingin.net/">Speaking in .NET</a>: <a title="Windows Phone Development QuickStarts" href="http://create.msdn.com/en-us/education/quickstarts">Windows Phone Development QuickStarts</a>.</p>
<p>Y, de nuevo una vez más, volvemos a msdn: <a title="Code Samples for Windows Phone" href="http://msdn.microsoft.com/en-us/library/ff431744%28VS.92%29.aspx">Code Samples for Windows Phone</a>.</p>
<p>Espero que estos enlaces os sean de utilidad. ¿Qué hacéis aún leyendo? ¡Empezad a programar!.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2011/10/24/felicidades-windows-phone-algunos-enlaces-de-interes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Automatizar acciones entre redes sociales con ifttt</title>
		<link>http://www.juanmasantoyo.es/index.php/2011/10/22/automatizar-acciones-entre-redes-sociales-con-ifttt/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2011/10/22/automatizar-acciones-entre-redes-sociales-con-ifttt/#comments</comments>
		<pubDate>Sat, 22 Oct 2011 20:54:35 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[general]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=703</guid>
		<description><![CDATA[Llevo toda la tarde trabajando en el blog, y lo último que me quedaba por hacer era vincular la cuenta de twitter con la página de facebook. Facebook provee una aplicación con la que es muy sencillo configurarlo, de forma &#8230; <a href="http://www.juanmasantoyo.es/index.php/2011/10/22/automatizar-acciones-entre-redes-sociales-con-ifttt/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Llevo toda la tarde trabajando en el blog, y lo último que me quedaba por hacer era vincular la cuenta de twitter con la página de facebook.</p>
<p>Facebook provee una aplicación con la que es muy sencillo configurarlo, de forma que publicando en el muro de mi página en Facebook se reflejase en twitter, pero a mí me interesaba hacerlo alrevés; que publicando en twitter se reflejase en facebook. Eso no es tan simple.</p>
<p>Lo mejor que he encontrado es ifttt, un servicio que, dándole permisos; permite automatizar diversos tipos de tareas entre distintas redes sociales.</p>
<p>La idea es montar disparadores, y configurarlos mediante la regla &#8220;si ocurre esto, haz aquello&#8221;. La potencia es brutal, y permite simplificar y centralizar todas las acciones que queramos automatizar entre distintas redes sociales.</p>
<p>Os recomiendo que le echéis un ojo: <a title="Ir a ifttt" href="http://www.ifttt.com/">ifttt</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2011/10/22/automatizar-acciones-entre-redes-sociales-con-ifttt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cambios</title>
		<link>http://www.juanmasantoyo.es/index.php/2011/10/22/cambios/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2011/10/22/cambios/#comments</comments>
		<pubDate>Sat, 22 Oct 2011 19:25:43 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[general]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=700</guid>
		<description><![CDATA[He aprovechado las vacaciones para hacer algunos cambios en el blog. Básicamente, he renovado el diseño y he abierto una cuenta de twitter donde se reflejarán las nuevas entradas, y además iré poniendo cosillas interesantes de vez en cuando. A &#8230; <a href="http://www.juanmasantoyo.es/index.php/2011/10/22/cambios/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>He aprovechado las vacaciones para hacer algunos cambios en el blog.</p>
<p>Básicamente, he renovado el diseño y he abierto una cuenta de twitter donde se reflejarán las nuevas entradas, y además iré poniendo cosillas interesantes de vez en cuando. A partir de ahora, me podréis encontrar también por <a title="Juanma Santoyo en twitter" href="http://twitter.com/#!/juanmasantoyoes">@juanmasantoyoes</a>.</p>
<p>¡Saludos!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2011/10/22/cambios/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducción a Entity framework Code First</title>
		<link>http://www.juanmasantoyo.es/index.php/2011/10/22/introduccion-a-entity-framework-code-first/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2011/10/22/introduccion-a-entity-framework-code-first/#comments</comments>
		<pubDate>Sat, 22 Oct 2011 19:17:07 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[efcf]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=648</guid>
		<description><![CDATA[En general, para usar Entity Framework; debemos tomar como punto de partida una base de datos existente. Por lo tanto, sin base de datos no podemos crear el modelo de persistencia. Pero todo eso ha cambiado ya que desde hace &#8230; <a href="http://www.juanmasantoyo.es/index.php/2011/10/22/introduccion-a-entity-framework-code-first/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>En general, para usar Entity Framework; debemos tomar como punto de partida una base de datos existente. Por lo tanto, sin base de datos no podemos crear el modelo de persistencia.</p>
<p>Pero todo eso ha cambiado ya que desde hace unos pocos meses disponemos de <em>Entity framework Code First</em>. <em>EFCF</em> nos permite crear el modelo de base de datos tomando como punto de partida una serie de clases. Estas clases, serán nuestro modelo de persistencia, y también serán el punto de partida desde el cual <em>EFCF</em> creará el esquema de la base de datos.<br />
<span id="more-648"></span></p>
<h3>Convención sobre configuración</h3>
<p>Una de las grandes cosas de <em>EFCF</em> es que sigue una pauta de &#8220;Convención sobre configuración&#8221;. Esto es, que <strong>nosotros no debemos configurar todas las cosas que programamos en nuestro modelo de persistencia, si no que <em>EFCF</em> lo hará por nosotros</strong> siempre que sigamos las convenciones de <em>EFCF</em>. Por lo tanto, cuando programemos nuestro modelo de persistencia deberemos conocer y aplicar dichas convenciones.</p>
<p>Las convenciones de las que hablo en realidad son muy pocas y muy coherentes. Ahora puede parecer que son un inconveniente por tener que conocerlas todas, pero nada más lejos de la realidad: veremos cómo gracias a esta política el desarrollo de un modelo de persistencia se vuelve un proceso simple y muy rápido.</p>
<p>Por supuesto, todas las convenciones son configurables. Si quieres complicarte la vida, tú mismo con tu mecanismo…</p>
<p>Por ejemplo, supongamos que estamos creando la clase de persistencia para la tabla <em>Producto</em>. Lo primero que deberíamos hacer, es crear un campo que sea la clave primaria. ¿Cómo determinamos cuál es ese campo?. Fácil: Por convención, la clave primaria será aquel campo numérico llamado <em>Id</em>. Cabe destacar que nada en <em>EFCF</em> es case-sensitive (aunque el modelo de persistencia sí lo es).</p>
<h3>Ejemplo práctico</h3>
<p>Vamos a hacer un pequeño ejemplo para ilustrar el funcionamiento de <em>EFCF</em>. Crearemos un pequeño modelo de persistencia para dos tablas: <em>Producto</em> y <em>Categoría</em>.</p>
<p>Ya podemos imaginar el resto de la historia: ambas tablas tendrán un identificador y un nombre. Además, la tabla producto estará relacionada con la tabla categoría; de forma que un producto tenga una categoría asociada y desde una categoría se pueda acceder a la colección de todos los productos asociados.</p>
<h4>Instalando Entity framework Code First</h4>
<p>Deberemos descargar e instalar <em>EFCF</em> para poder dotar a Visual Studio de las nuevas características. <a title="Entity framework Code First" href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;id=26660">Descarga Entity Framework Code First aquí</a>.</p>
<p>El orden de instalación es:</p>
<ol>
<li>EF_JUNE_2011_CTP.msi</li>
<li>DS_JUNE_2011_CTP.msi</li>
<li>EFTools.msi</li>
</ol>
<h4>Las entidades</h4>
<p>Crearemos un proyecto de tipo <em>Librería de clases</em> donde programaremos las clases que representarán las entidades. Atención aquí: debemos crear el proyecto bajo el framework <em>Microsoft Entity Framework June 2011 CTP</em>. El proyecto se llamará <em>EFCFTest.Entities</em>.</p>
<p><img class="aligncenter size-full wp-image-671" title="crear entities" src="http://www.juanmasantoyo.es/wp-content/uploads/2011/10/crear-entities.png" alt="crear entities" width="800" height="450" /></p>
<p>Crearemos una clase llamada <em>Categoria.cs</em>. En esta clase crearemos dos campos: uno será el identificador y el otro el nombre de la categoría.</p>
<pre class="brush:csharp">namespace EFCFTest.Entities
{
    public class Categoria
    {
        public long Id {get; set;}
        public string Nombre { get; set; }
    }
}</pre>
<p>Como veis, el campo <em>Id</em> es numérico. Un campo que se llame <em>Id</em> y sea numérico se convierte por convención en la clave primaria de la entidad. Además, es autoincrementable.</p>
<p>Vamos a crear ahora la clase <em>Producto.cs</em>.</p>
<pre class="brush:csharp">namespace EFCFTest.Entities
{
    public class Producto
    {
        public long Id { get; set; }
        public string Nombre { get; set; }
        public int Stock { get; set; }
    }
}</pre>
<p>Esta clase se parece mucho a la anterior, pero le he añadido un campo de Stock.</p>
<p>Solo nos queda un pequeño pero importantísimo detalle: Tenemos que programar la relación entre las entidades. Lo lógico aquí es que un producto se clasifique en una categoría y que una categoría tenga asociada una colección de productos. Pues no se hable más, vamos allá:</p>
<p>Empecemos por la clase <em>Producto</em>. Por convención, para asociar una entidad <em>Categoría</em> a la clase producto lo haremos añadiendo estos campos a la clase <em>Producto</em>.</p>
<pre class="brush:csharp">public long CategoriaId { get; set; }
public virtual Categoria Categoria { get; set; }</pre>
<p>Voy a explicar primero la segunda de estas dos propiedades: cumple dos características muy importantes:</p>
<ul>
<li>Es del tipo <em>Categoria</em>. Esto es así porque su valor será la entidad categoría con en la que está clasificado el producto.</li>
<li>Es virtual. Esto es importante, ya que determina que es una propiedad de navegación.</li>
</ul>
<p>La primera propiedad también cumple dos características:</p>
<ul>
<li>Es del mismo tipo que la clave primaria de <em>Categoria</em>. Esto tiene que ser así porque almacenará dicho valor.</li>
<li>El nombre de la propiedad es la concatenación de el nombre de la propiedad de navegación <em>Categoria</em> y el nombre de la clave primaria en la entidad <em>Categoria</em>, que es <em>Id</em>.</li>
</ul>
<p>Ahora vamos a crear la relación desde la clase <em>Categoria</em>. Aquí lo que queremos es una colección de productos, por lo que añadiremos la siguiente propiedad:</p>
<pre class="brush:csharp">public virtual ICollection&lt;Producto&gt; Productos { get; set; }</pre>
<p>Los aspectos a destacar en esta propiedad son:</p>
<ul>
<li>Al igual que la propiedad <em>Categoria</em> de la entidad <em>Producto</em>, es una propiedad de navegación y por lo tanto debe ser virtual.</li>
<li>Lógicamente, el tipo de la colección es <em>Producto</em>.</li>
</ul>
<p>Las colecciones merecen un tratamiento un poco especial, ya que por defecto las colecciones son referencias vacías. Podemos modificar el objeto para que las colecciones vengan siempre inicializadas. Es sencillo, sólo deberemos añadir un constructor en nuestra clase. Realmente, en el constructor podríamos inicializar cualquier valor que queramos:</p>
<pre class="brush:csharp">public Categoria()
{
	Productos = new List();
}</pre>
<p>Con esto ya hemos acabado con las entidades. Como veis, el principio de convención sobre configuración nos obliga a hacer las cosas de una determinada manera, pero las convenciones son sencillas de aprender y nos ahorrarán mucho tiempo.</p>
<h4>El contexto.</h4>
<p>El contexto es el entorno que nos permitirá trabajar con las Entidades. Se trata de un objeto que usaremos para acceder a la capa de persistencia.</p>
<p>Vamos a crear un nuevo proyecto tipo <em>Librería de clases</em> donde programaremos el contexto de nuestra aplicación. Al igual que el anterior, este proyecto debe crearse bajo el framework <em>Microsoft Entity Framework June 2011 CTP</em>.</p>
<p><img class="aligncenter size-full wp-image-670" title="crear context" src="http://www.juanmasantoyo.es/wp-content/uploads/2011/10/crear-context.png" alt="crear context" width="800" height="450" /></p>
<p>Este nuevo proyecto, extenderá de clases propias de <em>EFCF</em>, por lo que deberemos añadir una referencia a su DLL. Si has instalado <em>EFCF</em> tal y como indica este artículo, deberías encontrar la DLL en <em>C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.2\System.Data.Entity.dll</em>. Esto no tiene porqué ser así en tu entorno, ya que hay otras formas de instalar <em>EFCF</em>. También habrá que añadir una referencia al proyecto <em>EFCFTest.Entities</em> para poder hacer uso de las entidades que hemos creado previamente.</p>
<p>De momento, sólo vamos a añadir una clase. Quizás parezca absurdo crear un proyecto que va a contener una única clase, pero es más una cuestión de concepto y de escalabilidad: El contexto y las entidades no son exactamente lo mismo, por lo que no deberían estar juntos. El día de mañana, podríamos necesitar más contextos, o quizás necesitemos añadir lógica adicional a nuestro contexto.</p>
<p>La clase se llamará <em>EFCFTestContext</em>. Este nombre es importante, ya que por convención, es el nombre que recibirá el esquema de la base de datos que cree el contexto (el contexto es el encargado de crear la base de datos si no existe).</p>
<p>La clase es sencilla, sólo necesitará el siguiente código:</p>
<pre class="brush:csharp">using System.Data.Entity;
using VoyAlCine.Entities;
namespace EFCFTest.Context
{
    public class EFCFTestContext : DbContext
    {
        public DbSet&lt;Categoria&gt; Categorias { get; set; }
        public DbSet&lt;Producto&gt; Productos { get; set; }
    }
}</pre>
<p>Como se puede ver, también he indicado los using que vamos a necesitar para importar las referencias que acabamos de añadir.</p>
<p>Las cosas a destacar de éste código son:</p>
<ul>
<li>La clase contexto hereda de DbContext. Esta es una clase de la DLL de <em>EFCF</em>.</li>
<li>Crearemos un DbSet por cada entidad que hayamos creado. La clase DbSet también es parte de <em>EFCF</em>.</li>
</ul>
<p>Sólo queda una cosa por decir sobre la clase contexto: sería lógico querer cambiar el nombre del esquema de la base de datos. Esto es sencillo, solo debemos añadir un constructor que sobre escriba la llamada al constructor de DbContext. Como parámetro, le pasaremos el nombre que deseamos darle a la base de datos:</p>
<pre class="brush:csharp">public EFCFTestContext() : base("EFCFTest")
{
}</pre>
<h3>Creamos una aplicación de prueba</h3>
<p>Por último, vamos a crear una aplicación que nos sirva para realizar algunas pruebas sobre nuestro nuevo modelo de persistencia.</p>
<p>Vamos a crear una aplicación de consola llamada <em>EFCFTest.ConsoleApp</em>. No hay que olvidar que debemos seleccionar el framework <em>Microsoft Entity Framework June 2011 CTP</em>.</p>
<p>Lo primero que haremos será agregar a las referencias los proyectos de entidades y contexto. También debemos añadir una referencia a la DLL <em>System.Data.Entity.dll</em>, tal y como hicimos en el proyecto de contexto.</p>
<p><img class="aligncenter size-full wp-image-669" title="crear consoleapp" src="http://www.juanmasantoyo.es/wp-content/uploads/2011/10/crear-consoleapp.png" alt="crear consoleapp" width="800" height="450" /></p>
<p>Otra cosa importante que debemos hacer, es añadir la cadena de conexión a la base de datos. Esta cadena de conexión se debe añadir al <em>app.config</em> del proyecto, en el nodo <em>configuration/connectionStrings</em>. La cadena de conexión deberá ser algo como:</p>
<pre class="brush:plain">Data Source=&lt;Servidor de la base de datos&gt;;Initial catalog=&lt;em&gt;EFCF&lt;/em&gt;Test;Integrated Security=True;MultipleActiveResultSets=True</pre>
<p>Atención al parámetro <em>Data Source</em>. Este debe ser el servidor donde esté la base de datos. He puesto las marcas <em>&lt;</em> y <em>&gt;</em> por legibilidad, pero debéis quitarlas cuando pongáis el servidor.</p>
<p>Al final, vuestro app.config debe quedar más o menos así:</p>
<pre class="brush:xml">&lt;configuration&gt;
  &lt;!-- … --&gt;
  &lt;connectionStrings&gt;
    &lt;add name="VoyAlCineContext"
         connectionString="Data Source=&lt;Servidor de la base de datos&gt;;Initial catalog=&lt;em&gt;EFCF&lt;/em&gt;Test;Integrated Security=True;MultipleActiveResultSets=True"
         providerName="System.Data.SqlClient"/&gt;
  &lt;/connectionStrings&gt;
&lt;/configuration&gt;</pre>
<p>El parámetro <em>providerName</em> es muy importante.</p>
<h4>Crear registros</h4>
<p>Vamos a crear algunos registros. Lo primero que debemos hacer es crear una instancia del contexto al cual queramos acceder:</p>
<pre class="brush:csharp">EFCFTestContext context = new &lt;em&gt;EFCF&lt;/em&gt;TestContext();

Vamos a crear una categoría y le vamos a asociar dos productos:

Categoria Quesos = new Categoria();
Quesos.Nombre = "Quesos";

Quesos.Productos.Add(new Producto()
{
  Nombre = "Queso Edam"
  , Stock = 10
});

Quesos.Productos.Add(new Producto()
{
  Nombre = "Queso Havarti"
  , Stock = 5
});

context.Categorias.Add(quesos);

context.SaveChanges();</pre>
<p>Lo que he hecho es lo siguiente: He creado un objeto <em>Categoria</em>, le he inicializado la propiedad <em>Nombre</em>, y después le he incluido en la colección de productos dos objetos <em>Producto</em>. Por último, lo más importante: he añadido la categoría al contexto, y he persistido los cambios con el método <em>SaveChanges</em>. Este último paso es esencial, ya que es lo que guarda en base de datos todos los objetos que hemos añadido al contexto.</p>
<p>Para tener un conjunto de datos más decente, voy a crear un par de categorías más, con sus respectivos productos. Haré algunas modificaciones sobre el código anterior que no voy a reflejar en este artículo por cuestiones de legibilidad. Como siempre, al final encontraréis una versión descargable de este ejemplo donde podréis consultar todo el código fuente.</p>
<p>Si ahora ejecutamos nuestra aplicación de consola, veremos cómo se crea nuestra base de datos y se inicializa con unos cuantos datos. Vamos a añadir un poco de código más al programa. Este código sólo servirá para monitorizar lo que está ocurriendo, y para evitar que la aplicación se cierre automáticamente (todas las aplicaciones de consola se cierran al acabar, a no ser que nosotros programemos que no sea así).</p>
<p>El código que añadiremos será:</p>
<ol>
<li>Después de añadir una categoría al contexto añadiremos ésta línea:
<pre class="brush:csharp">Console.WriteLine("Se ha creado la categoría {0}", Quesos.Nombre);</pre>
</li>
<li>Al final de nuestro programa, forzaremos que la aplicación espere la introducción de la tecla enter, de forma que no se cerrará hasta que se pulse enter:
<pre class="brush:csharp">Console.WriteLine("Operación finalizada. Pulsa ENTER para salir...");
Console.ReadLine();</pre>
</li>
</ol>
<p>Por último, antes de ejecutar la aplicación. Hay que tener en cuenta que se deba establecer la aplicación de consola como el proyecto de inicio:</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-690" title="establecer como proyecto de inicio" src="http://www.juanmasantoyo.es/wp-content/uploads/2011/10/establecer-proyecto-inicio.png" alt="establecer como proyecto de inicio" width="590" height="400" /></p>
<p>&nbsp;</p>
<p>Lo que ocurra en nuestra pantalla debería parecerse a esto:</p>
<p><img class="aligncenter size-full wp-image-673" title="resultados creacion" src="http://www.juanmasantoyo.es/wp-content/uploads/2011/10/resultados-creacion.png" alt="resultados creacion" width="677" height="342" /></p>
<p>Seguramente habréis notado un tiempo de inactividad excesivo al ejecutar la aplicación por primera vez. Esto se debe a que la base de datos no existía y se ha creado. Si accedéis a la base de datos con un gestor como el Microsoft SQL Management Studio o similar, podréis ver cómo se ha creado la base de datos:</p>
<p><img class="aligncenter size-full wp-image-681" title="bdd creada" src="http://www.juanmasantoyo.es/wp-content/uploads/2011/10/bdd-creada.png" alt="bdd creada" width="302" height="360" /></p>
<p>Por supuesto, también se habrán creado los registros que hemos programado.</p>
<h4>Seleccionar registros</h4>
<p>Ahora vamos a ver cómo podemos seleccionar registros de la base de datos.</p>
<p>Lo primero que haremos será comentar el código anterior, ya que no queremos que se vuelvan a crear más registros. Sólo dejaremos sin comentar las líneas que crean el objeto Context y las que pausan la ejecución del programa. Comentaremos incluso la llamada al método SaveChanges, ya que no queremos modificar el contenido de la base de datos.</p>
<p>Hay varias maneras de acceder al contenido. Por ejemplo, desde el objeto Context podríamos obtener un listado con todas las categorías:</p>
<pre class="brush:csharp">Console.WriteLine("nTodas las categorías:");
List&lt;Categoria&gt; Categorias = Context.Categorias.ToList&lt;Categoria&gt;();
foreach (Categoria Categoria in Categorias)
{
    Console.WriteLine("{0}t{1}", Categoria.Id, Categoria.Nombre);
}</pre>
<p>Podríamos usar <em>linq</em>, personalmente es el método que más me gusta:</p>
<pre class="brush:csharp">var ProductosQueso = from p in Context.Productos
where p.Nombre.ToLower().Contains("queso")
      select p;

Console.WriteLine("nProductos cuyo nombre contiene la subcadena "queso":");
foreach (Producto Producto in ProductosQueso)
{
    Console.WriteLine("t{0}.", Producto.Nombre);
}</pre>
<p><em>Linq</em> nos permitiría incluso hacer joins entre tablas:</p>
<pre class="brush:csharp">ProductosQueso = from p in Context.Productos
join c in Context.Categorias on p.Categoria equals c
where c.Nombre.ToLower() == "Quesos"
select p;

Console.WriteLine("nProductos en la categoría "Quesos":");
foreach (Producto Producto in ProductosQueso)
{
    Console.WriteLine("t{0}.", Producto.Nombre);
}</pre>
<p>También podríamos usar las <em>lambda expressions</em> de <em>linq</em>. Hacen el uso de <em>linq</em> más simple, pero no son tan potentes como usar <em>linq</em> directamente, y complican la lectura del código:</p>
<pre class="brush:csharp">List&lt;Producto&gt; ProductosFrutosSecos = Context.Productos.Where(
p =&gt; p.Categoria == Context.Categorias.FirstOrDefault(c =&gt; c.Nombre.ToLower() == "frutos secos"))
.ToList&lt;Producto&gt;();

Console.WriteLine("nProductos en la categoría "Frutos secos":");
foreach (Producto Producto in ProductosFrutosSecos)
{
    Console.WriteLine("t{0}.", Producto.Nombre);
}</pre>
<p>Por último, podríamos acceder a los elementos según el valor de su clave primaria. Es el método más simple de todos ya que permite seleccionar contenidos sin el uso de <em>linq</em>, pero sólo podríamos usarlo sabiendo la clave primaria del elemento que necesitamos, y no permite seleccionar conjuntos (solo elementos aislados):</p>
<pre class="brush:csharp">Categoria CategoriaRefrescos = Context.Categorias.Find(2);
Console.WriteLine("nProductos en la categoría "Refrescos":");
foreach (Producto Producto in CategoriaRefrescos.Productos)
{
    Console.WriteLine("t{0}.", Producto.Nombre);
}</pre>
<p><img class="aligncenter size-full wp-image-674" title="resultados listado" src="http://www.juanmasantoyo.es/wp-content/uploads/2011/10/resultados-listado.png" alt="resultados listado" width="677" height="366" /></p>
<pre class="brush:csharp"></pre>
<h4>Borrar registros</h4>
<p>Borrar los registros existentes no puede ser más sencillo:</p>
<pre class="brush:csharp">Categoria CategoriaFrutosSecos = (from c in Context.Categorias
    where c.Nombre.ToLower() == "frutos secos"
    select c).First&lt;Categoria&gt;();

Context.Categorias.Remove(CategoriaFrutosSecos);

Console.WriteLine("nSe ha borrado la categoría {0}", (CategoriaFrutosSecos).Nombre);</pre>
<p>Cómo veis, tan solo hay que localizar el registro a borrar y usar el método Remove.</p>
<h4>Descarga el ejemplo</h4>
<p>Como intento hacer siempre, os dejo la <a href="http://www.juanmasantoyo.es/wp-content/uploads/2011/10/EFCFTest.Entities.zip">descarga del ejemplo</a>.</p>
<h3>¡Hemos terminado!</h3>
<p>En éste artículo hemos explicado cómo crear una base de datos y su modelo de persistencia con <em>Entity framework Code First</em> y también hemos añadido varios ejemplos de cómo usarla. Ha sido un artículo muy completo que espero que os resulte útil.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2011/10/22/introduccion-a-entity-framework-code-first/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Instalar el entorno de desarrollo de Surface 2</title>
		<link>http://www.juanmasantoyo.es/index.php/2011/08/01/instalar-el-entorno-de-desarrollo-de-surface-2/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2011/08/01/instalar-el-entorno-de-desarrollo-de-surface-2/#comments</comments>
		<pubDate>Mon, 01 Aug 2011 15:34:04 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[surface]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=637</guid>
		<description><![CDATA[Instalar el entorno de desarrollo para la Surface 2 es relatívamente sencillo, ya que el proceso es similar a la instalación del entorno para Surface 1. De hecho es más sencillo si cabe, ya que en ésta ocasión la instalación &#8230; <a href="http://www.juanmasantoyo.es/index.php/2011/08/01/instalar-el-entorno-de-desarrollo-de-surface-2/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Instalar el entorno de desarrollo para la Surface 2 es relatívamente sencillo, ya que el proceso es similar a la instalación del entorno para Surface 1. De hecho es más sencillo si cabe, ya que en ésta ocasión la instalación es totalmente compatible con Windows 7 y Visual Studio 2010, por lo que nos ahorraremos problemas.</p>
<p>Paso a comentar qué hace falta instalar con sus respectivos enlaces de descarga.<br />
<span id="more-637"></span> Visual Studio 2010</p>
<p>Obviamente, lo primero es contar con un buen entorno de programación. Los que aún no tengáis un Visual Studio 2010 en vuestras manos, sabed que se pueden obtener licencias gratuitas desde el programa para estudiantes <a title="Dreamspark" href="https://www.dreamspark.com/default.aspx">Deamspark</a>. Si no sois estudiantes, podéis haceros con una versión de <a title="Visual C# 2010 Express" href="http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-csharp-express">Visual C# 2010 Express</a>, que no tiene tantas funcionalidades como un Visual Studio; pero es gratiíto y sigue siendo un bien IDE.</p>
<p>Mi recomendación es que os hagáis con las versiones en inglés.</p>
<h3>XNA Framework redistributable 4.0</h3>
<p>Al igual que el SDK de Surface 1 requería del XNA Framework redistributable 2.0, para el SDK de Surface 2 necesitaremos el <a title="XNA Framework redistributable 4.0" href="http://www.microsoft.com/download/en/details.aspx?id=20914">XNA Framework redistributable 4.0</a>. Se puede descargar fácilmente desde el centro de descargas de Microsoft.</p>
<h3>SDK de Surface 2</h3>
<p>Ahora ya tenemos todo lo que necesitamos para instalar el <a title="Surface 2 SDK" href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;id=26716">SDK de Surface 2</a>. También se puede bajar desde el centro de descargas de Microsoft.</p>
<h3>Empezar a programar con el nuevo SDK</h3>
<p>Para empezar a tocar, podéis echarle un ojo a la <a title="Documentación de Surface 2 SDK en MSDN" href="http://msdn.microsoft.com/en-us/library/ff727815(Surface.20).aspx">nueva documentación de MSDN</a>.</p>
<p>¡A Programar!. Hay que hacer una mención especial a la nueva interfaz metro, y las nuevas herramientas de desarrollo. Ahora el emulador está totalmente integrado en Windows 7 y es mucho más agradable para los desarrolladores. Sobre todo si contamos con una pantalla táctil.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2011/08/01/instalar-el-entorno-de-desarrollo-de-surface-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Surface Shell dejó de funcionar</title>
		<link>http://www.juanmasantoyo.es/index.php/2011/06/18/surface-shell-dejo-de-funcionar/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2011/06/18/surface-shell-dejo-de-funcionar/#comments</comments>
		<pubDate>Sat, 18 Jun 2011 19:08:24 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[general]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=631</guid>
		<description><![CDATA[Me he pasado meses sin poder codificar una línea de código surface por un error que me traía de cabeza. Tal y como encabeza éste artículo, el error reza tal que así: &#8220;Surface Shell dejó de funcionar&#8221;, y se produce &#8230; <a href="http://www.juanmasantoyo.es/index.php/2011/06/18/surface-shell-dejo-de-funcionar/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Me he pasado meses sin poder codificar una línea de código surface por un error que me traía de cabeza.</p>
<p>Tal y como encabeza éste artículo, el error reza tal que así: <strong>&#8220;Surface Shell dejó de funcionar&#8221;</strong>, y se produce cada vez que el emulador de surface se intenta arrancar.</p>
<p>Como suele ocurrir en estos casos, la solución es obvia y absurda. Tan sólo es cuestión de instalar el <a title="Microsoft XNA Framework Redistributable 2.0" href="http://www.microsoft.com/downloads/en/details.aspx?familyid=15fb9169-4a25-4dca-bf40-9c497568f102&amp;displaylang=en">Microsoft XNA Framework Redistributable 2.0</a>.</p>
<p>En mi caso, tenía instalada la versión 3.1. Como soy un fenómeno, había asumido que la 3.1 sería tan válida como la 2.0 y cuando instalé el entorno de desarrollo de Surface instalé la versión equivocada.</p>
<p>Lo cierto es que ambas versiones pueden coexistir sin problemas en el sistema, así que si te ocurre éste error, sólo tienes que instalar el Microsoft XNA Framework Redistributable 2.0, no importa ni que desinstales el resto de versiones si no quieres.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2011/06/18/surface-shell-dejo-de-funcionar/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reaccionar a los objetos etiquetados en Microsoft Surface: el control TagVisualization.</title>
		<link>http://www.juanmasantoyo.es/index.php/2011/06/18/reaccionar-a-los-objetos-etiquetados-en-microsoft-surface-el-control-tagvisualization/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2011/06/18/reaccionar-a-los-objetos-etiquetados-en-microsoft-surface-el-control-tagvisualization/#comments</comments>
		<pubDate>Sat, 18 Jun 2011 18:19:17 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[general]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=560</guid>
		<description><![CDATA[Hace unos meses, hablaba por aquí sobre los contactos en pantalla (Detección y gestión de contactos en una Surface). Aunque hay otra forma de reaccionar a los contactos etiquetados: En Surface es muy común posicionar un gráfico justo bajo el &#8230; <a href="http://www.juanmasantoyo.es/index.php/2011/06/18/reaccionar-a-los-objetos-etiquetados-en-microsoft-surface-el-control-tagvisualization/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Hace unos meses, hablaba por aquí sobre los contactos en pantalla (<a href="http://www.juanmasantoyo.es/index.php/2010/09/22/deteccion-y-gestion-de-contactos-en-una-surface/">Detección y gestión de contactos en una Surface</a>).</p>
<p>Aunque hay otra forma de reaccionar a los contactos etiquetados: En Surface es muy común posicionar un gráfico justo bajo el objeto etiquetado. Algo como esto:</p>
<div style="overflow: hidden;"><a href="http://www.juanmasantoyo.es/wp-content/uploads/2011/03/ejemploTagVisualization02.png"><img class="alignleft size-full wp-image-576" title="ejemploTagVisualization02" src="http://www.juanmasantoyo.es/wp-content/uploads/2011/03/ejemploTagVisualization02.png" alt="" width="200" height="200" /></a> <a href="http://www.juanmasantoyo.es/wp-content/uploads/2011/03/ejemploTagVisualization03.png"><img class="alignleft size-full wp-image-577" title="ejemploTagVisualization03" src="http://www.juanmasantoyo.es/wp-content/uploads/2011/03/ejemploTagVisualization03.png" alt="" width="200" height="200" /></a> <a href="http://www.juanmasantoyo.es/wp-content/uploads/2011/03/ejemploTagVisualization01.png"><img class="alignleft size-full wp-image-575" title="ejemploTagVisualization01" src="http://www.juanmasantoyo.es/wp-content/uploads/2011/03/ejemploTagVisualization01.png" alt="" width="200" height="200" /></a></div>
<p>Este gráfico debe posicionarse siempre bajo nuestro objeto y orientarse según lo haga el objeto. Además, dependiendo del tipo de etiqueta o su valor, este gráfico puede tener comportamientos distintos. Para los casos en los que queremos responder a un objeto etiquetado de esta forma, tenemos dos objetos que nos facilitarán la vida: El <em>TagVisualizer</em> y el <em>TagVisualization</em>.</p>
<p><span id="more-560"></span></p>
<p><a id="TagVisualization" name="TagVisualization"></a></p>
<h3>El control TagVisualization.</h3>
<p>El objeto TagVisualization nos proporciona rápidamente un control de usuario que tiene como único objetivo posicionarse bajo los elementos etiquetados que toquen la pantalla. Como todos los controles de usuario, se basa en una parte XAML, donde especificamos la parte gráfica del control de usuario, y una parte en C#, donde especificamos la funcionalidad (por ejemplo, podemos programar un método que lance una animación en el TagVisualization, o un método para mostrar un mensaje).</p>
<p>Los objetos TagVisualization se pueden crear desde el menú de añadir elementos de Visual Studio:</p>
<div id="attachment_564" class="wp-caption aligncenter" style="width: 610px"><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/11/011-e1289506680708.png"><img class="size-full wp-image-564" title="01" src="http://www.juanmasantoyo.es/wp-content/uploads/2010/11/011-e1289506680708.png" alt="Abrir la pantalla de &quot;Añadir nuevo elemento&quot;" width="600" height="426" /></a><p class="wp-caption-text">Abrir la pantalla de &quot;Añadir nuevo elemento&quot;</p></div>
<div id="attachment_562" class="wp-caption aligncenter" style="width: 610px"><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/11/02-e1289506850604.png"><img class="size-full wp-image-562" title="02" src="http://www.juanmasantoyo.es/wp-content/uploads/2010/11/02-e1289506850604.png" alt="Añadir el control de usuario &quot;Tag Visualization&quot;" width="600" height="473" /></a><p class="wp-caption-text">Añadir el control de usuario &quot;Tag Visualization&quot;</p></div>
<p>Pero en realidad, un control TagVisualization son sirve de poco sin su respectivo TagVisualizer.</p>
<h3>El control TagVisualizer.</h3>
<p>Si un TagVisualization es el control de usuario que se posiciona bajo un contacto etiquetado, un TagVisualizer es el control que gestiona todos los TagVisualization que tenemos. Tiene varias funciones:</p>
<ol>
<li>Determina el área de la pantalla que será sensible al posicionamiento de objetos etiquetados.</li>
<li>Discrimina entre los diferentes tipos de etiquetas, de forma que según indiquemos, muestra un TagVisualization o otro en función de la etiqueta del objeto.</li>
<li>Detecta los eventos de entrada y salida de los contactos. Estos eventos son especialmente útiles porque desde ellos podemos ejecutar funcionalidades del TagVisualization.</li>
</ol>
<h3>Mejor con un ejemplo.</h3>
<p>Vamos a programar un pequeño ejemplo para ver más cláramente cómo funcionan ambos objetos. El ejemplo consistirá en una región de pantalla donde podremos posicionar un objeto etiquetado. Al posicionarlo aparecerá debajo un círculo, el cual se mostrará con una animación sencilla.</p>
<h4>Creamos el proyecto y la pantalla principal.</h4>
<p>Crearemos un proyecto de Surface con Visual Studio. Lo llamaremos &#8220;ContactosEtiquetados&#8221;. En lo particular, a mi me gusta cargarme la pantalla que viene por defecto y crearme la mía &#8220;Main.xaml&#8221;. Recordad que si hacéis esto, tenéis que cambiar el valor del atributo <em>StartupUri</em> en el archivo <em>App.config</em>.</p>
<p>En la pantalla inicial, no nos complicamos. Únicamente meteremos el <em>TagVisualizer</em>, y le daremos algun detalle gráfico para poder visualizarlo en pantalla:</p>
<pre class="brush:xml">&lt;s:SurfaceWindow x:Class="ContactosEtiquetados.Main"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="http://schemas.microsoft.com/surface/2008"
    Title="ContactosEtiquetados"
    Width="1024" Height="768"
    Loaded="SurfaceWindow_Loaded"
&gt;
    &lt;s:SurfaceWindow.Resources&gt;
        &lt;ImageBrush x:Key="WindowBackground" Stretch="None" Opacity="0.6" ImageSource="pack://application:,,,/Resources/MainBackground.jpg"/&gt;
    &lt;/s:SurfaceWindow.Resources&gt;

    &lt;Grid Background="{StaticResource WindowBackground}" &gt;
        &lt;s:TagVisualizer
            x:Name="Visualizer"
            Width="700" Height="550"
            HorizontalAlignment="Center" VerticalAlignment="Center"
            BorderBrush="White" BorderThickness="2""&gt;

        &lt;/s:TagVisualizer&gt;
    &lt;/Grid&gt;
&lt;/s:SurfaceWindow&gt;</pre>
<p>Sólo destacar que al <em>TagVisualizer</em> le he asignado dos eventos: <em>VisualizationAdded</em> y <em>VisualizationRemoved</em>. Efectívamente, se lanzarán cuando entre y salga un contacto respectívamente. Tambien he asignado el evento Loaded a la <em>SurfaceWindow</em>.</p>
<h4>Creamos el objeto TagVisualization.</h4>
<p>Crear un objeto <em>TagVisualization</em> es sencillo: el propio Visual Studio lo hace desde la ventana de &#8220;Añadir nuevo elemento&#8221; (<a title="TagVisualization" href="#TagVisualization">lo hemos visto antes</a>).</p>
<p>En el nuevo control introduciremos dos gráficos y una grid. Los gráficos estarán dentro de la grid, y serán un círculo grande sin relleno y otro más pequeño con relleno. Éste último lo posicionaremos sobre el contorno del más grande. Por último, añadiremos un RotateTransform a la grid que contiene ambos círculos:</p>
<pre class="brush:xml">&lt;s:TagVisualization x:Class="ContactosEtiquetados.TagVisualization"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="http://schemas.microsoft.com/surface/2008"
    Loaded="TagVisualization_Loaded"
    Width="300" Height="300"&gt;
    &lt;Grid&gt;
        &lt;Grid&gt;
            &lt;Ellipse Width="200" Height="200" Stroke="Red" StrokeThickness="2" /&gt;

            &lt;Ellipse Width="50" Height="50" Fill="Red" Margin="200,0,0,0" /&gt;

            &lt;Grid.RenderTransform&gt;
                &lt;RotateTransform CenterX="150" CenterY="150" Angle="0" /&gt;
            &lt;/Grid.RenderTransform&gt;
        &lt;/Grid&gt;
    &lt;/Grid&gt;
&lt;/s:TagVisualization&gt;</pre>
<h4>Gestión de los contactos etiquetados.</h4>
<p>La gestión de los contactos que recibe el <em>TagVisualizer </em>se basa en objetos <em>TagVisualizationDefinition</em>. A un <em>TagVisualizer</em> se le añaden una o varias definiciones. Cada definición asociará el <em>TagVisualizer </em>con un <em>TagVisualization </em>y además nos permitirá discriminar los contactos según el valor de la etiqueta. Lo normal es crear las definiciones que necesitemos extendiendo la clase <em>TagVisualizationDefinition</em>. Por ejemplo, en nuestro caso sólo reaccionaremos a los contactos de tipo <em>Identity</em>. Creamos la clase <em>ContactosEtiquetadosVisualizationDefinition.cs</em>.</p>
<pre class="brush:csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Surface.Presentation.Controls;
using Microsoft.Surface.Presentation;
using System.Windows;

namespace ContactosEtiquetados
{
    class ContactosEtiquetadosVisualizationDefinition : TagVisualizationDefinition
    {
        protected override bool Matches(TagData tag)
        {
            if (tag.Type == TagType.Identity) return true;
            else return false;
        }

        protected override Freezable CreateInstanceCore()
        {
            return new ContactosEtiquetadosVisualizationDefinition();
        }
    }
}</pre>
<p>El método Matches es la clave para determinar qué contactos hay que tener en cuenta.</p>
<p>Ahora añadimos la definición al objeto TagVisualizer. Lo haremos en el evento Load de la ventana inicial:</p>
<pre class="brush:csharp">        private void SurfaceWindow_Loaded(object sender, RoutedEventArgs e)
        {
            TagVisualizationDefinition definition = new ContactosEtiquetadosVisualizationDefinition();
            definition.Source = new Uri("TagVisualization.xaml", UriKind.Relative);
            definition.LostTagTimeout = 1000;
            Visualizer.Definitions.Add(definition);
        }</pre>
<p>Comentamos un poco: La propiedad Source símplemente hace referencia al <em>XAML</em> del objeto <em>TagVisualization</em>. La propiead LostTagTimeOut define un tiempo de espera antes de &#8220;matar&#8221; al <em>TagVisualization</em>, en caso de que el contacto deje de estar en contacto con la pantalla. Dicho de otra forma, el <em>TagVisualization </em>no desaparecería hasta que el contacto no lleve más de un segundo perdido.</p>
<h4>Programamos la animación del TagVisualization.</h4>
<p>Para animar el control <em>TagVisualization </em>rescataremos un artículo que escribí sobre el tema hace un tiempo: <a title="Animar transformaciones en WPF con el método BeginAnimation" href="http://www.juanmasantoyo.es/index.php/2010/07/06/animar-transformaciones-en-wpf-con-el-metodo-beginanimation/">Animar transformaciones en WPF con el método BeginAnimation</a>. Aplicar la animación al <em>TagVisualization</em> es simple:</p>
<p>Primero, vamos a crear un método en el <em>TagVisualization</em> que inicie la animación:</p>
<pre class="brush:csharp">private void StartAnimation()
{
    DoubleAnimation animacion = new DoubleAnimation();

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

    // La animaci&amp;Atilde;&amp;sup3;n se repite continuamente
    animacion.RepeatBehavior = RepeatBehavior.Forever;

    this.Rotacion.BeginAnimation(RotateTransform.AngleProperty, animacion);
}</pre>
<p>Ésta animación puede ser iniciada en el evento Loaded:</p>
<pre class="brush:csharp">private void Visualization_Loaded(object sender, RoutedEventArgs e)
{
    this.StartAnimation();
}</pre>
<h3>¡Hemos acabado!</h3>
<p class="brush:csharp">Con ésto ya podemos programar muchas respuestas interesantes a nuestros contactos etiquetados.</p>
<p class="brush:csharp">El ejemplo descargable lo tenéis aquí: <a href="http://www.juanmasantoyo.es/wp-content/uploads/2011/06/ContactosEtiquetados.zip">Contactos etiquetados</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2011/06/18/reaccionar-a-los-objetos-etiquetados-en-microsoft-surface-el-control-tagvisualization/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>¡Nos vemos por Facebook!</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/10/21/nos-vemos-por-facebook/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/10/21/nos-vemos-por-facebook/#comments</comments>
		<pubDate>Thu, 21 Oct 2010 22:46:57 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[general]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=555</guid>
		<description><![CDATA[He creado una página en Facebook para darle un poco más de difusión al blog, así que desde hoy ya podéis ser fans y esas historias. Realmente creo que no hacía falta, ya que el posicionamiento en Google no es &#8230; <a href="http://www.juanmasantoyo.es/index.php/2010/10/21/nos-vemos-por-facebook/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>He creado una página en Facebook para darle un poco más de difusión al blog, así que desde hoy ya podéis ser fans y esas historias.</p>
<p>Realmente creo que no hacía falta, ya que el posicionamiento en Google no es malo y bueno, creo que los contenidos se propagan adecuadamente, pero tenía ganas de trastear un poco con el asunto.</p>
<p>Arriba a la izquierda, sobre el cuadro de búsqueda; he colocado el botón de Facebook para compartir los artículos. El desgraciado ha sido más difícil de posicionar de lo que esperaba.</p>
<p><span id="more-555"></span></p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/10/21/nos-vemos-por-facebook/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Crear eventos propios en aplicaciones de Surface</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/10/02/crear-eventos-propios-en-aplicaciones-de-surface/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/10/02/crear-eventos-propios-en-aplicaciones-de-surface/#comments</comments>
		<pubDate>Sat, 02 Oct 2010 08:34:41 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[surface]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=535</guid>
		<description><![CDATA[En las aplicaciones de Surface, los eventos son básicos. La mayoría de las veces, nos bastará con los eventos que nos proporciona el SDK, pero en ocasiones necesitamos algo más específico, o incluso reaccionar a una combinación de eventos. Necesitamos &#8230; <a href="http://www.juanmasantoyo.es/index.php/2010/10/02/crear-eventos-propios-en-aplicaciones-de-surface/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>En las aplicaciones de Surface, los eventos son básicos.</p>
<p>La mayoría de las veces, nos bastará con los eventos que nos proporciona el SDK, pero en ocasiones necesitamos algo más específico, o incluso reaccionar a una combinación de eventos. Necesitamos eventos propios: poder disparar el evento cuando queramos, pasar la información que queramos; y que otra clase que esté escuchando el evento realice una acción.</p>
<p>De eso hablaré en este artículo. Comentaré un pequeño ejemplo donde veremos cómo podemos implementar un evento de doble tap (lo llamaremos <em>DoubleTap</em>). Este evento no viene implementado en el SDK de Surface, y como análogo al por todos conocido &#8220;Doble Click&#8221; de los PC, puede resultar muy útil.</p>
<p><span id="more-535"></span></p>
<h3>Implementación de un evento DoubleTap.</h3>
<p>Vamos a organizarnos un poco: ¿cómo vamos a implementar el <em>DoubleTap</em>?. Pues bien, en esencia un <em>DoubleTap</em> no es más que dos <em>ContactDown </em>en un periodo corto de tiempo. El <em>ContactDown </em>es un evento que sí que viene implementado en el SDK, así que sólo necesitamos almacenar el instante en el que se realizó el primer <em>ContactDown </em>para comprobar si el tiempo entre dos <em>ContactDown </em>es lo suficientemente corto. De serlo, se dispararía el <em>DoubleTap</em>. Es decir, que necesitamos:</p>
<ul>
<li>Un manejador para el evento <em>ContactDown</em>.</li>
<li>Una propiedad global de tipo <em>DateTime </em>que almacenará el momento del último <em>ContactDown</em>.</li>
</ul>
<p>Todo esto lo programaríamos dentro del objeto al que queremos dotar de la capacidad de lanzar <em>DoubleTap</em>. En nuestro caso, será un control de usuario (lo normal).</p>
<h3>Programamos el control de usuario.</h3>
<p>Gráficamente lo haremos fácil: un rectángulo. Este es el <em>XAML</em>:</p>
<pre class="brush:xml">&lt;s:SurfaceUserControl x:Class="ProgramarEventosPropios.DoubleTapUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="http://schemas.microsoft.com/surface/2008"&gt;
    &lt;Grid&gt;
        &lt;Rectangle Fill="Red" Width="100" Height="100" /&gt;
    &lt;/Grid&gt;
&lt;/s:SurfaceUserControl&gt;</pre>
<p>Y ahora, el<em> C#</em>. Aquí es donde programaremos el evento <em>DoubleTap</em>, pero primero, vayamos a lo principal: gestionar el evento <em>ContactDown</em> y el tiempo entre dos <em>ContactDown</em>:</p>
<pre class="brush:csharp">DateTime LastContactDown = DateTime.MinValue;
TimeSpan MaxMilis = TimeSpan.FromMilliseconds(700);

protected override void OnContactDown(ContactEventArgs e)
{
    base.OnContactDown(e);

    if (this.LastContactDown == DateTime.MinValue)
    {
        this.LastContactDown = DateTime.Now;
    }
    else
    {
        TimeSpan time = DateTime.Now - this.LastContactDown;

         if (time &lt;= this.MaxMilis)
         {
             RaiseDoubleTapEvent(time);
         }

         this.LastContactDown = DateTime.MinValue;
    }
}</pre>
<p>Varias cosas a comentar de este código:</p>
<ol>
<li>La variable <em>MaxMilis </em>sólo define el tiempo máximo entre <em>ContactDown</em>. Únicamente cuando el tiempo es inferior o igual, se considera un <em>DoubleTap</em>.</li>
<li>Por otra parte, mirad cómo asigno el evento <em>ContactDown</em>. Lo normal es asignar un manejador, pero en este caso hago una sobreescritura del método <em>OnContactDown</em>. Los eventos también se pueden asignar así, aunque sinceramente, yo prefiero añadir un manejador en el <em>XAML </em>(en esta ocasión lo hago con sobreescritura a modo ilustrativo).</li>
<li>Por último, fijaos que en caso de cumplirse el <em>DoubleTap</em>, ejecuto el método <em>RaiseDoubleTapEvent </em>con el parámetro <em>time</em>. El método lo veremos ahora, se trata del disparador del evento. Los disparadores no son necesarios, pero sí muy recomendables. El parámetro time lo paso por que es la información que quiero enviar con el evento (en un objeto <em>EventArgs</em>). De esta forma, los manejadores del evento <em>DoubleTap </em>pueden saber cuánto tiempo pasó entre los dos <em>ContactDown </em>(no es una información demasiado útil, pero para ilustrar como funcionan los objetos <em>EventArgs </em>nos viene de perlas).</li>
</ol>
<p>Y ahora empieza lo bueno: programamos el evento.</p>
<p>En realidad, hay que programar varias cosas:</p>
<ol>
<li>El evento.</li>
<li>Las gestión de los manejadores que quieran escuchar el evento.</li>
<li>Un disparador para el evento.</li>
</ol>
<h4>Programamos el evento.</h4>
<p>En realidad lo único complejo es el registro del evento. Y no es que sea complejo, es sólo que es muy configurable (y requiere muchos parámetros).</p>
<pre class="brush:csharp">public delegate void DoubleTapEventHandler(object sender, DoubleTapEventArgs e);

public static readonly RoutedEvent DoubleTapEvent = EventManager.RegisterRoutedEvent(
	"DoubleTap",
	RoutingStrategy.Direct,
	typeof(DoubleTapEventHandler),
	typeof(DoubleTapUserControl));</pre>
<p>Lo primero, definimos el manejador del evento. Le damos nombre, y; sobre todo; determinamos que los argumentos vienen como un objeto <em>DoubleTapEventArgs</em>. Este objeto lo crearemos luego, y tiene la particularidad de tener una propiedad para almacenar el tiempo entre los dos <em>ContactDown </em>¿recordáis que al disparador le pasábamos un parámetro <em>time</em>?.</p>
<p>En cuanto al registro del evento, le pasamos cuatro parámetros:</p>
<ol>
<li>El nombre del evento.</li>
<li>La estrategia del evento. Puede ser <em>Direct</em>, <em>Tunnel </em>o <em>Bubble</em>. Sirve para determinar la dirección de propagación. En este caso, <em>Direct </em>no se propaga.</li>
<li>El tipo del manejador. No es casualidad que coincida con lo declarado en la línea 1.</li>
<li>El tipo del objeto que dispara el evento. En este caso, el nombre de nuestro control de usuario.</li>
</ol>
<h4>La gestión de manejadores.</h4>
<p>Esto se parece a los típicos <em>getters </em>/ <em>setters</em> de .Net. Se trata simplemente de gestionar lo que ocurre cuando se añaden o se quitan manejadores de los eventos.</p>
<pre class="brush:csharp">public event DoubleTapEventHandler DoubleTap
{
    add
    {
        AddHandler(DoubleTapEvent, value);
    }
    remove
    {
        RemoveHandler(DoubleTapEvent, value);
    }
}</pre>
<h4>El disparador.</h4>
<p>Este método se encarga de lanzar el evento. Un disparador debería hacer tres cosas:</p>
<ol>
<li>Recibir por parámetro los valores que hay que enviar como argumentos del evento.</li>
<li>Montar un objeto <em>EventArgs</em> que contenga los valores a enviar.</li>
<li>Lanzar el evento.</li>
</ol>
<p>Es muy sencillo:</p>
<pre class="brush:csharp">private void RaiseDoubleTapEvent(TimeSpan TimeBetweenTaps)
{
    DoubleTapEventArgs Args = new DoubleTapEventArgs(TimeBetweenTaps);
    Args.RoutedEvent = DoubleTapUserControl.DoubleTapEvent;

    RaiseEvent(Args);
}</pre>
<p>Y este sería el objeto <em>DoubleTapEventArgs</em>. La idea es que es una extensión del objeto <em>RoutedEventArgs</em>.</p>
<pre class="brush:csharp">public class DoubleTapEventArgs : RoutedEventArgs
{
	TimeSpan timeBetweenTaps = TimeSpan.MinValue;
	public TimeSpan TimeBetweenTaps
	{
	  get { return timeBetweenTaps; }
	}

	public DoubleTapEventArgs(TimeSpan TimeBetweenTaps) : base()
	{
		this.timeBetweenTaps = TimeBetweenTaps;
	}
}</pre>
<p>Con esto ya hemos programado un control de usuario capaz de detectar y disparar un evento <em>DoubleTap</em>. ¿Cómo lo usamos?. Vamos a añadir este objeto a la ventana inicial de la aplicación y lo vemos. En realidad, como si fuese un evento normal y corriente.</p>
<p>Este es el <em>XAML </em>de la ventana:</p>
<pre class="brush:xml">&lt;s:SurfaceWindow x:Class="ProgramarEventosPropios.SurfaceWindow1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="http://schemas.microsoft.com/surface/2008"
    xmlns:self="clr-namespace:ProgramarEventosPropios"
    Title="ProgramarEventosPropios"
&gt;
    &lt;s:SurfaceWindow.Resources&gt;
        &lt;ImageBrush x:Key="WindowBackground" Stretch="None" Opacity="0.6" ImageSource="pack://application:,,,/Resources/WindowBackground.jpg"/&gt;
    &lt;/s:SurfaceWindow.Resources&gt;

    &lt;Grid Background="{StaticResource WindowBackground}" &gt;
        &lt;self:DoubleTapUserControl x:Name="DoubleTapUC" DoubleTap="DoubleTapUC_DoubleTap" /&gt;
    &lt;/Grid&gt;</pre>
<p>Y desde el C# programamos el manejador del evento:</p>
<pre class="brush:csharp">void DoubleTapUC_DoubleTap(object sender, DoubleTapEventArgs e)
{
    Debug.WriteLine("Double Tap. Tiempo: {0}", e.TimeBetweenTaps.TotalMilliseconds);
}</pre>
<h3>Descarga del ejemplo.</h3>
<p>Y como no podía ser de otra forma, os dejo aquí la descarga a un pequeño proyecto que es el que programé para redactar este artículo.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/10/CrearEventosPropios.zip">Crear eventos propios.</a></p>
<h3>¡Hemos acabado!.</h3>
<p>Con esto ya tenemos un evento propio funcionando. Este tipo de eventos nos serán muy útiles en nuestras aplicaciones, y nos solucionarán la vida en muchas ocasiones. No está de más decir que realmente este tipo de eventos se pueden implementar en cualquier aplicación WPF, no sólo en las aplicaciones de Surface.</p>
<p>Espero que hayáis encontrado útil este artículo.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/10/02/crear-eventos-propios-en-aplicaciones-de-surface/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Arquitectura de capas en aplicaciones para Microsoft Surface</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/09/30/arquitectura-de-capas-en-aplicaciones-para-microsoft-surface/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/09/30/arquitectura-de-capas-en-aplicaciones-para-microsoft-surface/#comments</comments>
		<pubDate>Thu, 30 Sep 2010 19:10:46 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[surface]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=521</guid>
		<description><![CDATA[En la primera aplicación que hice para Surface, cometí un gran error de arquitectura que bajo mi punto de vista estropeó un poco lo que yo considero que fue un buen trabajo. Ahora que estoy trabajando en otra aplicación para &#8230; <a href="http://www.juanmasantoyo.es/index.php/2010/09/30/arquitectura-de-capas-en-aplicaciones-para-microsoft-surface/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>En <a href="http://www.juanmasantoyo.es/index.php/2010/07/06/video-de-rent-a-car-surface-by-bizzit/">la primera aplicación que hice para Surface</a>, cometí un gran error de arquitectura que bajo mi punto de vista estropeó un poco lo que yo considero que fue un buen trabajo. Ahora que estoy trabajando en otra aplicación para Surface, me propuse desde el primer día no repetirlo. A la solución que he encontrado la he llamado arquitectura de capas. No estoy inventando nada, pues en la programación gráfica dividir la interfaz  en capas es muy común. Este artículo realmente sólo propone una forma de  hacerlo en una aplicación WPF orientada a Surface.<br />
<span id="more-521"></span></p>
<h3>Mi gran error.</h3>
<p>Me dí cuenta de que era realmente complicado gestionar las cosas que había en el <em>ScatterView</em>. Si veis el vídeo, comprobaréis que básicamente estoy hablando de tres tipos de elementos: los controles de usuario, el coche, y las imágenes del interior del coche. La solución por la que opté en aquel momento se basaba en usar métodos para introducir y eliminar cada elemento en el <em>ScatterView</em>, y registrar la existencia de cada uno en tres listas globales (una lista para cada tipo de elemento). De esa forma ponía y quitaba los elementos de cada tipo.</p>
<p>Era una mala solución, por que no permitía una gran modularización del código y sobrecargaba la clase principal del programa de funcionalidades que realmente no eran de su competencia. Todo se complicaba mucho más si tenemos en cuenta que no pude encapsular el <em>ScatterView </em>en un control de usuario como me hubiese gustado y lo tenía todo en la ventana inicial de la aplicación. En pocas palabras, aunque creo que algunos aspectos de la aplicación quedaron bastante bien, la ventana inicial era sucia y desordenada. El tiempo y la falta de experiencia me impidieron mejorar ese aspecto. Se podría decir que esa aplicación tiene un serio problema de arquitectura.</p>
<h3>La solución: Arquitectura de capas.</h3>
<p>Sin embargo, cuando inicié el desarrollo de la aplicación que tengo ahora entre manos, decidí desde el primer momento plantear las cosas de otro modo. No quería repetir el mismo error, sobre todo por que esta aplicación es aún más compleja en lo que respecta a los elementos libres por la pantalla y un error de esas características hubiese tenido un impacto negativo en la aplicación mucho más devastador.</p>
<p>El principal error que cometí inicialmente fue pensar que un <em>ScatterView </em>no puede posicionarse sobre otro. En realidad, sí es posible, y ambos <em>ScatterViews </em>son totalmente funcionales. Esto nos permite organizar los elementos en varios <em>ScatterViews</em>, uno sobre otro; como si fuesen capas.</p>
<p>Básicamente, para implementar esta arquitectura sólo necesitaremos:</p>
<ol>
<li>Diferentes controles de usuario que serán las capas.</li>
<li>Una clase estática o Singleton que se encargará de gestionar las interacciones entre capas.</li>
</ol>
<p>Cada capa se preocupa únicamente de sus competencias, mientras que para cualquier tipo de interacción con los elementos de las otras capas se usarán funcionalidades implementadas en la clase estática.</p>
<h3>Un ejemplo sencillo.</h3>
<p>No voy a complicarlo, ya que realmente sólo nos interesa ver cómo funcionaría esta arquitectura.</p>
<p>El ejemplo en cuestión será el siguiente: vamos a hacer dos capas en forma de controles de usuario. En cada capa vamos a poner un <em>ScatterView </em>y un <em>ScatterViewItem</em>.</p>
<p>La idea es que cuando un <em>ScatterViewItem </em>se mueva, el otro se posicionará en una posición reflejada. Es decir, reflejará las coordenadas X e Y del <em>ScatterViewItem </em>que hemos movido.</p>
<p>Obviamente, la comunicación entre controles de usuario que necesitamos se implementará con una clase estática.</p>
<h4>Las capas.</h4>
<p>Vamos a programar las dos capas. Serán dos controles prácticamente idénticos, sólo cambiaremos un par de características del <em>ScatterViewItem </em>(para que no se confundan). Los <em>ScatterViewItems </em>tendrán colores diferentes y ubicaciones diferentes (obviamente). Uno estará situado en el punto (100, 100) y el otro en su punto simétrico (924, 668). Para simplificar el asunto, haremos que los <em>ScatterViewItems </em>no se puedan rotar ni escalar.</p>
<p>Los controles de usuario se llamarán LayerA y LayerB, este es su <em>XAML</em>:</p>
<h5>LayerA.</h5>
<pre class="brush:xml">&lt;s:SurfaceUserControl x:Class="ArquitecturaDeCapas.LayerA"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="http://schemas.microsoft.com/surface/2008"&gt;
    &lt;Grid&gt;
        &lt;s:ScatterView&gt;
            &lt;s:ScatterViewItem x:Name="Svi"
                Orientation="0" Center="100,100"
                Width="50" Height="50"
                CanScale="False" CanRotate="False"
                ScatterManipulationDelta="ScatterViewItem_ScatterManipulationDelta"
            &gt;
                &lt;Rectangle Fill="Yellow" /&gt;
            &lt;/s:ScatterViewItem&gt;
        &lt;/s:ScatterView&gt;
    &lt;/Grid&gt;
&lt;/s:SurfaceUserControl&gt;</pre>
<h5>LayerB.</h5>
<pre class="brush:xml">&lt;s:SurfaceUserControl x:Class="ArquitecturaDeCapas.LayerB"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="http://schemas.microsoft.com/surface/2008"&gt;
    &lt;Grid&gt;
        &lt;s:ScatterView&gt;
            &lt;s:ScatterViewItem x:Name="Svi"
                Orientation="0" Center="924,668"
                Width="50" Height="50"
                CanScale="False" CanRotate="False"
                ScatterManipulationDelta="ScatterViewItem_ScatterManipulationDelta"
            &gt;
                &lt;Rectangle Fill="Red" /&gt;
            &lt;/s:ScatterViewItem&gt;
        &lt;/s:ScatterView&gt;
    &lt;/Grid&gt;
&lt;/s:SurfaceUserControl&gt;</pre>
<p>Como veis en ambos controles, los <em>ScatterViewItems </em>tienen asignado un manejador para el evento &#8220;<em>ScatterManipilationDelta</em>&#8220;. Este evento se lanza cada vez que una manipulación provoca un cambio en el <em>ScatterViewItem</em>, así que lo usaremos para notificar a la clase estática que el <em>ScatterViewItem</em> tiene una nueva posición (y la clase estática lo notificará a su vez a la otra capa).</p>
<p>Vamos pues a ver ese manejador. En ambas capas será igual, ya que será el método de la clase estática quien diferencie entre una capa o otra (esto no tendría por qué ser así).</p>
<h5>El manejador de <em>ScatterManipilationDelta.</em></h5>
<pre class="brush:csharp">private void ScatterViewItem_ScatterManipulationDelta(object sender, ScatterManipulationDeltaEventArgs e)
{
    ScatterViewItem svi = (ScatterViewItem) sender;
    Layers.NotifyNewPosition(this, svi.Center);
}</pre>
<p>Fijaos en el método <em>Layers.NotifyNewPosition</em>. Este método será el método que comunicará ambas capas. La idea es que haga dos cosas:</p>
<ol>
<li>Identifica la capa que llama al método.</li>
<li>Notifica a la otra capa la nueva posición respecto a la que debe reflejar su <em>ScatterViewItem</em>.</li>
</ol>
<p>Para identificar la capa que llama al método, vemos que se envía el parámetro <em>this</em>. Para saber la nueva posición del <em>ScatterViewItem</em>, envía el parámetro <em>svi.Center</em>.</p>
<p>Por otra parte, la clase estática informará a la otra capa de la nueva posición mediante un método público en la capa que deba ser notificada. En este caso, como la posición se refleja; también se harán los cálculos necesarios. El método público de cada capa, sería una cosa así:</p>
<pre class="brush:csharp">
public void ReflexSviPosition(Point Position)
{
    this.Svi.Center = new Point(1024 - Position.X, 768 - Position.Y);
}
</pre>
<p>Ahora que ya sabemos como son las capas, vamos a ver que forma tiene esa clase estática que nos comunicará ambas capas.</p>
<h5>Una clase estática para comunicar las distintas capas.</h5>
<p>A la capa en cuestión la llamaremos Layers. Como he dicho, puede ser estática o Singletone. Aunque seamos francos, realmente el único requisito que debe cumplir esta clase es que tiene que ser accesible por todas las capas que queramos relacionar.</p>
<pre class="brush:csharp">public static class Layers
{
	private static LayerA layerA = null;
	public static LayerA LayerA
	{
		get { return layerA; }
		set { layerA = value; }
	}

	private static LayerB layerB = null;
	public static LayerB LayerB
	{
		get { return Layers.layerB; }
		set { Layers.layerB = value; }
	}

	public static void NotifyNewPosition(SurfaceUserControl Layer, Point Position)
	{
		if(Layer.GetType() == typeof(LayerA))
		{
			layerB.ReflexSviPosition(Position);
		}
		else if(Layer.GetType() == typeof(LayerB))
		{
			layerA.ReflexSviPosition(Position);
		}
	}
}</pre>
<p>Podéis ver el método &#8220;<em>NotifyNewPosition</em>&#8221; y cómo hace la distinción de capas.</p>
<p>Otro aspecto muy importante de esta clase, son las propiedades <em>LayerA </em>y <em>LayerB</em>. No son más que referencias a las capas, para poder acceder posteriormente a ellas. ¿Dónde se inician estas propiedades? Pues allí donde estén las propias capas. En este caso es la ventana inicial de mi programa, que se llama Main.xaml.</p>
<h5>El contenedor de las capas.</h5>
<p>Este sería el xaml:</p>
<pre class="brush:xml">&lt;s:SurfaceWindow x:Class="ArquitecturaDeCapas.Main"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="http://schemas.microsoft.com/surface/2008"
    xmlns:self="clr-namespace:ArquitecturaDeCapas"

    Title="ArquitecturaDeCapas"
&gt;
    &lt;s:SurfaceWindow.Resources&gt;
        &lt;ImageBrush x:Key="WindowBackground" Stretch="None" Opacity="0.6" ImageSource="pack://application:,,,/Resources/MainBackground.jpg"/&gt;
    &lt;/s:SurfaceWindow.Resources&gt;

    &lt;Grid Background="{StaticResource WindowBackground}"&gt;
        &lt;self:LayerA x:Name="LayerA" /&gt;
        &lt;self:LayerB x:Name="LayerB" /&gt;
    &lt;/Grid&gt;
&lt;/s:SurfaceWindow&gt;</pre>
<p>Y también se necesita un poco de <em>C#</em> para guardar en la clase <em>Layers</em> las referencias a cada capa. En mi caso, he añadido estas dos líneas de código al final del constructor de <em>Main</em>.</p>
<pre class="brush:csharp">Layers.LayerA = this.LayerA;
Layers.LayerB = this.LayerB;</pre>
<p>De esta clase <em>Main </em>destacar tres cosas:</p>
<ol>
<li>Añadimos el namespace <em>self</em>, para poder incluír controles de usuario de nuestro proyecto.</li>
<li>Añadimos las dos capas.</li>
<li>Guardamos en <em>Layers </em>las referencias a nuestras capas. Yo lo he hecho al final del constructor, pero se podría hacer en el evento <em>Loaded</em>, por ejemplo.</li>
</ol>
<h3>Hemos acabado.</h3>
<p>Pues no hay mucho más que decir, ya tenemos dos <em>ScatterViews </em>sincronizados. Rápido, sencillo, y para toda la familia; espero que os ayude.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/09/30/arquitectura-de-capas-en-aplicaciones-para-microsoft-surface/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Detección y gestión de contactos en una Surface</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/09/22/deteccion-y-gestion-de-contactos-en-una-surface/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/09/22/deteccion-y-gestion-de-contactos-en-una-surface/#comments</comments>
		<pubDate>Wed, 22 Sep 2010 17:55:16 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[surface]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=508</guid>
		<description><![CDATA[A estas alturas de la película, uno ya debería tener claro que la base de las entradas de usuario en una Surface son los contactos. Da igual si tocamos la pantalla con un dedo o con toda la mano, con &#8230; <a href="http://www.juanmasantoyo.es/index.php/2010/09/22/deteccion-y-gestion-de-contactos-en-una-surface/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A estas alturas de la película, uno ya debería tener claro que la base de las entradas de usuario en una Surface son los contactos.</p>
<p>Da igual si tocamos la pantalla con un dedo o con toda la mano, con un trozo de madera; o si hemos colocado un elemento etiquetado: Todo se reduce a detectar un contacto y gestionarlo.</p>
<p>Por lo tanto, se podría decir que hay varios tipos de contactos. En este artículo vamos a ver qué tipos de contactos hay, cómo podemos detectarlos, y cómo podemos obtener información relevante sobre los mismos. No es un asunto complicado, pero sí es bastante amplio. A modo de resumen, en el artículo vamos a tratar los siguientes puntos:</p>
<ol>
<li>Tipos de contactos.</li>
<li>Reconocimiento de contactos.</li>
<li>Diferenciación de contactos.</li>
<li>Reconocer el mismo contacto en diferentes eventos.</li>
<li>Conocer los diferentes contactos que existen sobre un elemento.</li>
</ol>
<p><span id="more-508"></span></p>
<h3>Tipos de contactos.</h3>
<p>Básicamente, podemos considerar tres tipos diferentes de contactos:</p>
<h4>Dedos.</h4>
<p>La mayoría de contactos son dedos, ya que para el usuario, lo más natural y intuitivo casi siempre será hacer algo con el dedo sobre la pantalla.</p>
<h4>Etiquetas.</h4>
<p>Una de las características más interesantes de una Surface es la detección de etiquetas. Las etiquetas son unos gráficos que al entrar en contacto con la pantalla son reconocidos como tales y tienen un valor numérico determinado.</p>
<p>Existen dos tipos de etiquetas: Las <em>Byte Tags</em> y las <em>Identity Tags</em>. La principal diferencia entre ambas es que las <em>Byte Tags</em> pueden tomar 2<sup>8</sup> valores distintos, y los <em>Identity Tags</em> pueden tomar 2<sup>128</sup> valores diferentes (separados en dos campos de 2<sup>64</sup> y 2<sup>64</sup>).</p>
<div id="attachment_510" class="wp-caption aligncenter" style="width: 81px"><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/09/ByteTagC6.jpg"><img class="size-full wp-image-510" title="Byte Tag" src="http://www.juanmasantoyo.es/wp-content/uploads/2010/09/ByteTagC6.jpg" alt="Byte Tag" width="71" height="71" /></a><p class="wp-caption-text">Un Byte Tag</p></div>
<div id="attachment_511" class="wp-caption aligncenter" style="width: 118px"><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/09/IdentityTag.png"><img class="size-full wp-image-511" title="Identity Tag" src="http://www.juanmasantoyo.es/wp-content/uploads/2010/09/IdentityTag.png" alt="Identity Tag" width="108" height="109" /></a><p class="wp-caption-text">Un Identity Tag</p></div>
<h4>Objetos.</h4>
<p>En realidad, la Surface reacciona ante cualquier contacto sobre la pantalla, sea lo que sea. Puede ser el dorso de la mano, un trozo de madera, etc. Por lo tanto, catalogaremos como un &#8220;objeto&#8221; cualquier contacto que no sea ni un dedo ni una etiqueta.</p>
<h3>Reconocer contactos sobre un elemento.</h3>
<p>Reconocer los contactos sobre un elemento es relativamente sencillo. El propio SDK nos aporta eventos como &#8220;<em>ContactDown</em>&#8220;, &#8220;<em>ContactUp</em>&#8221; o &#8220;<em>ContactTapGesture</em>&#8221; que nos realizaran dicha tarea. De hecho, &#8220;<em>ContactDown</em>&#8221; nos servirá en la mayoría de las ocasiones.</p>
<p>Lo que sí requiere más conocimiento del tema es cómo diferenciar los diferentes tipos de contactos, y cómo obtener información relevante sobre cada uno.</p>
<p>Veamos un ejemplo sencillo de &#8220;<em>ContactDown</em>&#8220;. Por ejemplo, sobre un control de usuario que tengamos en pantalla.</p>
<p>Añadiremos la gestión del evento en el <em>XAML</em> del Control de usuario:</p>
<pre class="brush:xml">&lt;s:SurfaceUserControl x:Class="DeteccionDeContactos.MyUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="http://schemas.microsoft.com/surface/2008"

    ContactDown="SurfaceUserControl_ContactDown"
    Width="100" Height="100"
&gt;
    &lt;Grid Background="Red"&gt;

    &lt;/Grid&gt;
&lt;/s:SurfaceUserControl&gt;</pre>
<p>Y esto nos generará en el código <em>C#</em> un método como este:</p>
<pre class="brush:csharp">private void SurfaceUserControl_ContactDown(object sender, ContactEventArgs e)
{
}</pre>
<p>Podéis ver que por parámetro nos llegan dos objetos. Uno es el objeto <em>sender</em>, que no es más que el control de usuario que ha recogido el evento &#8220;<em>ContactDown</em>&#8220;. Por otra parte, nos llega el objeto <em>e</em>. Es un objeto del tipo &#8220;<em>ContactEventArgs</em>&#8220;, y contiene mucha información que nos puede interesar.</p>
<h3>Obtener información útil sobre los contactos.</h3>
<p>Antes de nada, vamos a ver cómo podemos saber qué tipo de contacto es. En realidad es sencillo, ya que las propiedades <em>e.Contact.IsContactRecognized</em> y <em>e.Contact.IsTagRecognized </em>nos lo revelarán:</p>
<pre class="brush:csharp">private void SurfaceUserControl_ContactDown(object sender, ContactEventArgs e)
{
    if (e.Contact.IsFingerRecognized)
    {
        Debug.WriteLine("Es un dedo.");
    }
    else if (e.Contact.IsTagRecognized)
    {
        Debug.WriteLine("Es un elemento etiquetado.");
    }
    else
    {
        Debug.WriteLine("Es un objeto.");
    }
}</pre>
<p>Ahora bien: ¿Más cosas que nos puedan interesar? Pues dependerá del tipo de contacto, obviamente. En general, algo que tienen en común todos los contactos es una posición en pantalla y una orientación (recordemos que una de las más geniales características de una Surface es poder detectar la orientación de un contacto). Nos lo dirán los métodos <em>e.Contact.GetPosition</em> y <em>e.Contact.GetOrientation</em>. Ambos métodos reciben por parámetro un elemento respecto al que orientarse. Lo más común es orientarse respecto al objeto que capturó el método, así que el parámetro <em>sender</em> que mencioné antes nos viene de perlas. El objeto <em>sender</em> en principio viene tipado como un objeto genérico, así que habrá que hacerle un casting. No debería ser un problema si tenemos claro quien lanzó el evento.</p>
<pre class="brush:csharp">private void SurfaceUserControl_ContactDown(object sender, ContactEventArgs e)
{
    MyUserControl uc = (MyUserControl) sender;

    Point position = e.GetPosition(uc);
    Double orientation = e.Contact.GetOrientation(uc);

    Debug.WriteLine("El contacto se ha producido en la posición: {0}, {1}.", position.X, position.Y);
    Debug.WriteLine("La orientación del contacto es de {0} grados.", orientation);

    if (e.Contact.IsFingerRecognized)
    {
        Debug.WriteLine("Es un dedo.");
    }
    else if (e.Contact.IsTagRecognized)
    {
        Debug.WriteLine("Es un elemento etiquetado.");
    }
    else
    {
        Debug.WriteLine("Es un objeto.");
    }
}</pre>
<p>Bueno, ya sabemos dónde se produjo el contacto, y sabemos también su orientación. Si el contacto fuese un dedo, no necesitamos saber más. Pero ¿Y si es un objeto etiquetado? Hay dos parámetros importantísimos que nos interesará conocer: el tipo de etiqueta y su valor. Conviene anticipar que si el contacto es de tipo <em>Identity</em>, el valor se separa en dos campos: la serie y el valor. La serie son los primeros 2<sup>64</sup> bits, el valor son los últimos 2<sup>64</sup> bits. Debemos considerar el objeto <em>e.Contacts.Tag</em> y sus propiedades.</p>
<pre class="brush:csharp">private void SurfaceUserControl_ContactDown(object sender, ContactEventArgs e)
{
    MyUserControl uc = (MyUserControl) sender;

    Point position = e.GetPosition(uc);
    Double orientation = e.Contact.GetOrientation(uc);

    Debug.WriteLine("El contacto se ha producido en la posición: {0}, {1}.", position.X, position.Y);
    Debug.WriteLine("La orientación del contacto es de {0} grados.", orientation);

    if (e.Contact.IsFingerRecognized)
    {
        Debug.WriteLine("Es un dedo.");
    }
    else if (e.Contact.IsTagRecognized)
    {
        Debug.WriteLine("Es un elemento etiquetado.");

        switch (e.Contact.Tag.Type)
        {
            case TagType.Byte:

                Byte byteTagValue = e.Contact.Tag.Byte.Value;

                Debug.WriteLine("Es un Byte Tag. Su valor es {0}.", byteTagValue);
                break;

            case TagType.Identity:

                long serie = e.Contact.Tag.Identity.Series;
                long identityTagValue = e.Contact.Tag.Identity.Value;

                Debug.WriteLine("Es un Identity Tag. Su serie es: {0}. Su valor es {1}.", serie, identityTagValue);
                break;
        }
    }
    else
    {
        Debug.WriteLine("Es un objeto.");
    }
}</pre>
<p>Por último, si el contacto es un objeto cualquiera, nos interesará saber su forma y el área que ocupa. El propio SDK nos ayuda creando un objeto <em>Ellipse</em> que tiene la forma aproximada del contacto. Nosotros podemos saber dónde está el centro del elipse, cuál es su tamaño y incluso el área exacta del objeto que toca la pantalla. Debemos observar los métodos <em>e.Contact.GetEllipse</em>,  <em>e.Contact.GetCenterPosition</em>, y la propiedad <em>e.Contact.PhysicalArea</em>. Los métodos para obtener los valores de la elipse también reciben por parámetro el objeto respecto al que deben calcularse. Igual que antes, lo normal sería usar el parámetro <em>sender</em>.</p>
<pre class="brush:csharp">private void SurfaceUserControl_ContactDown(object sender, ContactEventArgs e)
{
    MyUserControl uc = (MyUserControl) sender;

    Point position = e.GetPosition(uc);
    Double orientation = e.Contact.GetOrientation(uc);

    Debug.WriteLine("El contacto se ha producido en la posición: {0}, {1}.", position.X, position.Y);
    Debug.WriteLine("La orientación del contacto es de {0} grados.", orientation);

    if (e.Contact.IsFingerRecognized)
    {
        Debug.WriteLine("Es un dedo.");
    }
    else if (e.Contact.IsTagRecognized)
    {
        Debug.WriteLine("Es un elemento etiquetado.");

        switch (e.Contact.Tag.Type)
        {
            case TagType.Byte:

                Byte byteTagValue = e.Contact.Tag.Byte.Value;

                Debug.WriteLine("Es un Byte Tag. Su valor es {0}.", byteTagValue);
                break;

            case TagType.Identity:

                long serie = e.Contact.Tag.Identity.Series;
                long identityTagValue = e.Contact.Tag.Identity.Value;

                Debug.WriteLine("Es un Identity Tag. Su serie es: {0}. Su valor es {1}.", serie, identityTagValue);
                break;
        }
    }
    else
    {
        Double area = e.Contact.PhysicalArea;
        Ellipse ellipse = e.Contact.GetEllipse(uc);
        Point ellipseCenter = e.Contact.GetCenterPosition(uc);

        Debug.WriteLine("Es un objeto.");
        Debug.WriteLine("La elipse aproximada que contiene el contacto es ancho: {0}, alto: {1}", ellipse.Width, ellipse.Height);
        Debug.WriteLine("El punto central de la elipse es: {0}, {1}", ellipseCenter.X, ellipseCenter.Y);
    }
}</pre>
<h3>Reconocer el mismo contacto en diferentes eventos.</h3>
<p>Los contactos en realidad disparan más de un evento. Por ejemplo, un mismo contacto primero genera un &#8220;<em>ContactDown</em>&#8221; y por último generará un &#8220;<em>ContactUp</em>&#8220;. Entonces, ¿Cómo saber que son el mismo?. Para ello usaremos la propiedad<em> e.Contact.Id</em>. El mismo contacto, en diferentes eventos; conservará el mismo Id.</p>
<h3>Conocer los diferentes contactos sobre un elemento.</h3>
<p>Y para acabar, algo que también nos puede ser de utilidad es conocer los diferentes contactos que hay sobre un elemento. Para ello, podemos usar la propiedad <em>ContactsOver</em> que nos proporcionan los controles de usuario. Esto es una lista de objetos <em>Contact</em>, por lo que a cada elemento se le podrían aplicar todas las propiedades y métodos vistos en este artículo.</p>
<h3>Hemos acabado.</h3>
<p>Bueno, acabamos de pegar un buen repaso a los contactos de Surface. Dejo la descarga a un ejemplo que desarrollé para escribir este artículo.</p>
<p><a href="http://www.juanmasantoyo.es/wp-content/uploads/2010/09/DeteccionDeContactos.zip">Deteccion de contactos (VS 2010)</a></p>
<p>El contenido de este artículo debería ser suficiente para que cualquier hombre de bien desarrolle aplicaciones bastante decentes para Microsoft Surface, pero el que tenga dudas o necesite más información sobre algún aspecto que no dude en comentarlo por aquí. Yo mismo sigo aprendiendo sobre el tema, así que cualquier ayuda que os pueda prestar también me ayuda a mí.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/09/22/deteccion-y-gestion-de-contactos-en-una-surface/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Navegador basado en Chromium para integrar en aplicaciones WPF</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/09/03/navegador-basado-en-chromium-para-integrar-en-aplicaciones-wpf/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/09/03/navegador-basado-en-chromium-para-integrar-en-aplicaciones-wpf/#comments</comments>
		<pubDate>Fri, 03 Sep 2010 18:32:53 +0000</pubDate>
		<dc:creator>Juanma</dc:creator>
				<category><![CDATA[.net]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[surface]]></category>

		<guid isPermaLink="false">http://www.juanmasantoyo.es/?p=504</guid>
		<description><![CDATA[Desde hace semanas, intento encontrar la manera de identificar un usuario en Facebook desde una aplicación de Surface (WPF)&#8230; sin mucho éxito por el momento (de conseguir algo, será seguro una gran guarrería, que por supuesto publicaré en el blog). &#8230; <a href="http://www.juanmasantoyo.es/index.php/2010/09/03/navegador-basado-en-chromium-para-integrar-en-aplicaciones-wpf/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Desde hace semanas, intento encontrar la manera de identificar un usuario en Facebook desde una aplicación de Surface (WPF)&#8230; sin mucho éxito por el momento (de conseguir algo, será seguro una gran guarrería, que por supuesto publicaré en el blog).</p>
<p>No obstante, hice algunas preguntas por el blog de desarrolladores de Surface en MSDN USA, y es ahí donde me recomendaron este navegador para integrar en aplicaciones WPF:</p>
<p><a href="http://chriscavanagh.wordpress.com/2009/08/25/a-real-wpf-webbrowser/">http://chriscavanagh.wordpress.com/2009/08/25/a-real-wpf-webbrowser/</a></p>
<p>El proyecto es muy interesante: han aprovechado que el código de Chromium es libre para hacer una adaptación del mismo en WPF. Para que quede más claro, estoy hablando de un control de usuario 100% funcional, que puede ser integrado en aplicaciones WPF y que es una alternativa al control WebBrowser (el problema de este es que no es más que el Internet Explorer integrado en la aplicación).</p>
<p>En realidad este navegador no es exáctamente lo que necesito para mi aplicación y no lo he probado, pero como después de semanas de investigación esto es lo más interesante que me he encontrado, quería comentarlo.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/09/03/navegador-basado-en-chromium-para-integrar-en-aplicaciones-wpf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducción al componente ScatterView de Surface (2: ScatterViews con C#)</title>
		<link>http://www.juanmasantoyo.es/index.php/2010/08/03/introduccion-al-componente-scatterview-de-surface-parte-2/</link>
		<comments>http://www.juanmasantoyo.es/index.php/2010/08/03/introduccion-al-componente-scatterview-de-surface-parte-2/#comments</comments>
		<pubDate>Tue, 03 Aug 2010 05:27:06 +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=352</guid>
		<description><![CDATA[Ya hemos visto como podemos usar los ScatterView a base de XAML, pero muchas veces vamos a tener la necesidad de tratarlos desde C#. En este artículo, veremos cómo podemos trabajar con ScatterViews de forma dinámica. Preparamos el proyecto Antes &#8230; <a href="http://www.juanmasantoyo.es/index.php/2010/08/03/introduccion-al-componente-scatterview-de-surface-parte-2/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Ya hemos visto como podemos <a href="http://www.juanmasantoyo.es/index.php/2010/04/08/introduccion-al-componente-scatterview-de-surface-parte-1/">usar los <em>ScatterView</em> a base de <em>XAML</em></a>, pero muchas veces vamos a tener la necesidad de tratarlos desde <em>C#</em>.</p>
<p>En este artículo, veremos cómo podemos trabajar con ScatterViews de forma dinámica.<br />
<span id="more-352"></span></p>
<h3>Preparamos el proyecto</h3>
<p>Antes de iniciar el Visual Studio, debemos haber iniciado el emulador de Surface que viene con el <em>SDK</em>. Si no lo has hecho así, cierra el Visual Studio y inícialo todo en el orden correcto.</p>
<p>Usaremos el proyecto <em>HelloScatterView</em> que creamos en el primer artículo, y crearemos una nueva ventana <em>XAML</em> llamada &#8220;<em>CSharpSample</em>&#8220;. Tendremos que modificar el archivo <em>App.xml</em> (atrubito <em>StartupUri</em>) para que inicie la aplicación en la nueva ventana.</p>
<h3>ScatterViews simples con C#</h3>
<p>Vamos a considerar un <em>XAML</em> muy básico, sin <em>ScatterViewItems</em>. Sí que vamos a añadir tres botones que nos proporcionarán un mínimo de funcionalidad.</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;DockPanel&gt;
			&lt;UniformGrid Background=&quot;Black&quot; Height=&quot;50&quot; DockPanel.Dock=&quot;Top&quot; Columns=&quot;3&quot;&gt;
				&lt;s:SurfaceButton Content=&quot;Add&quot; Click=&quot;Add&quot; Foreground=&quot;White&quot;/&gt;
				&lt;s:SurfaceButton Content=&quot;Remove&quot; Click=&quot;Remove&quot; Foreground=&quot;White&quot;/&gt;
				&lt;s:SurfaceButton Content=&quot;Clear&quot; Click=&quot;Clear&quot; Foreground=&quot;White&quot;/&gt;
			&lt;/UniformGrid&gt;
			&lt;s:ScatterView x:Name=&quot;Scatter&quot;/&gt;
		&lt;/DockPanel&gt;
	&lt;/s:SurfaceWindow&gt;
</pre>
<p>Por ahora esto es todo el <em>XAML</em> que vamos a usar. La parte importante del código, la hacemos desde <em>C#</em>, en el archivo <em>CSharpSample.xaml.cs</em>.</p>
<p>Antes de continuar vamos a dejar claro que hará cada botón:</p>
<ul>
<li>El botón Add añadirá un <em>ScatterViewItem</em> con una de las imágenes (se seguirá un orden cíclico).</li>
<li>El botón Remove quitará el último <em>ScatterViewItem</em> añadido.</li>
<li>El botón Clear quitará todos los <em>ScatterViewItems</em>.</li>
</ul>
<h4>Inicializamos</h4>
<p>Creamos en el <em>.cs</em> una propiedad global que será una lista con los nombres de las imágenes, y otra propiedad que será un <em>String</em> con la ruta del directorio que las contiene, de forma que al concatenar el directorio con nombre de imagen tengamos la ruta completa. Daremos los correspondientes valores a ambas propiedades.</p>
<pre class="brush:csharp">
namespace HelloScatterView
{
    public partial class CSharpSample : SurfaceWindow
    {
        string folder = string.Empty;
        List&lt;string&gt; images = new List&lt;string&gt;();

        public CSharpSample()
        {
            this.folder = &quot;Resources/Img/&quot;;

            images.Add(&quot;fuente_tres_chorros.jpg&quot;);
            images.Add(&quot;kiyoumizu_dera.jpg&quot;);
            images.Add(&quot;laputa_robot.jpg&quot;);

            InitializeComponent();

            // Add handlers for Application activation events
            AddActivationHandlers();
        }
	}
}
</pre>
<h4>Eventos de los botones</h4>
<p>El evento click del botón añadir creará un ScatterViewItem, le asignará la imagen y lo añadirá al contenedor ScatterView. Para saber que imagen añadir, se basará en el total de imágenes añadidas.</p>
<pre class="brush:csharp">
private void Add(object sender, RoutedEventArgs e)
{
	// Calculamos el indice de la imagen a mostrar en función de la cantidad de elementos en el ScatterView
	int index = this.Scatter.Items.Count % this.images.Count;

	// Creamos el ScatterViewItem que vamos a añadir
	BitmapImage bmp = new BitmapImage(new Uri(this.folder + this.images[index], UriKind.Relative));
	Image img = new Image();
	img.Source = bmp;

	ScatterViewItem svi = new ScatterViewItem();
	svi.Content = img;

	Scatter.Items.Add(svi);
}
</pre>
<p>El evento click del botón eliminar, accederá a la última imagen añadida en el contenedor ScatterView y la eliminará:</p>
<pre class="brush:csharp">
private void Remove(object sender, RoutedEventArgs e)
{
	// Averiguamos el índice del último elemento añadido
	int index = this.Scatter.Items.Count - 1;

	if (index &gt;= 0)
	{
		this.Scatter.Items.Remove(this.Scatter.Items[index]);
	}
}
</pre>
<p>El evento click del botón borrar limpiará complétamente el contenedor ScatterView:</p>
<pre class="brush:csharp">
private void Clear(object sender, RoutedEventArgs e)
{
	this.Scatter.Items.Clear();
}
</pre>
<h3>Añadir ScatterViews con Data Binding</h3>
<p>Pero vamos a aprovechar las características de <em>.Net</em> para añadir los ScatterViewItems de una forma más potente. En realidad, podemos definir un origen de datos de forma que <em>.Net</em> añadirá todas las imágenes que contenga al contenedor ScatterView.</p>
<p>Dicho de otra forma, en pocas líneas de código podemos conseguir añadir al ScatterView todas las imágenes que haya, por ejemplo; en un directorio determinado. Vamos a hacer un ajuste en el constructor de CSharpSample y en el nodo s:ScatterView del XAML:</p>
<h4>En el C#</h4>
<pre class="brush:csharp">
public CSharpSample()
{
	this.folder = &quot;Resources/Img/&quot;;

	images.Add(&quot;fuente_tres_chorros.jpg&quot;);
	images.Add(&quot;kiyoumizu_dera.jpg&quot;);
	images.Add(&quot;laputa_robot.jpg&quot;);

	InitializeComponent();

	// Add handlers for Application activation events
	AddActivationHandlers();

	String[] files = System.IO.Directory.GetFiles(&quot;Resources/Img&quot;, &quot;*.jpg&quot;);
	this.Scatter.ItemsSource = files;
}
</pre>
<p>Lo importante son las últimas lineas: obtienen la lista de imágenes en un directorio y la establecen como el origen de datos del ScatterView.</p>
<h4>En el XAML#</h4>
<pre class="brush:xml">
&lt;s:ScatterView x:Name=&quot;Scatter&quot;&gt;
	&lt;s:ScatterView.ItemTemplate&gt;
		&lt;DataTemplate&gt;
			&lt;s:ScatterViewItem&gt;
				&lt;Image Source=&quot;{Binding}&quot; /&gt;
			&lt;/s:ScatterViewItem&gt;
		&lt;/DataTemplate&gt;
	&lt;/s:ScatterView.ItemTemplate&gt;
&lt;/s:ScatterView&gt;
</pre>
<p>Lo importante es el nodo ItemTemplate: hemos establecido una plantilla que es la que usarán los elementos en el origen de datos.</p>
<h3>Es todo por hoy</h3>
<p>Ahora ya sabemos crear ScatterVirews desde <em>XAML</em> y desde C#, pero esto es sólo el principio. Como comenté en el primer artículo, un ScatterViewItem es mucho más que una imagen; y eso es lo que veremos en el próximo artículo sobre ScatterViews.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.juanmasantoyo.es/index.php/2010/08/03/introduccion-al-componente-scatterview-de-surface-parte-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<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 &#8230; <a href="http://www.juanmasantoyo.es/index.php/2010/07/06/animar-transformaciones-en-wpf-con-el-metodo-beginanimation/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></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>9</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 &#8230; <a href="http://www.juanmasantoyo.es/index.php/2010/07/06/video-de-rent-a-car-surface-by-bizzit/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></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"><param name="movie" value="http://www.youtube.com/v/ax-0BToUTGo" /><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><embed wmode="opaque" src="http://www.youtube.com/v/ax-0BToUTGo" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></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>3</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 &#8230; <a href="http://www.juanmasantoyo.es/index.php/2010/06/11/ocultar-el-texto-de-un-input-submit/">Seguir leyendo <span class="meta-nav">&#8594;</span></a>]]></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>
	</channel>
</rss>

