<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3057613996558002471</id><updated>2024-11-06T03:10:59.226+00:00</updated><category term="csharp"/><category term="javascript"/><category term="tips"/><category term="aspnet"/><category term="entity framework"/><category term="general"/><category term="knockout"/><category term="mvc"/><category term="evento"/><category term="html5"/><category term="jQuery"/><category term="metro"/><category term="visual studio"/><category term="windows 8"/><category term="css"/><category term="dbmigrations"/><category term="log4net"/><category term="nodejs"/><category term="npm"/><category term="sql injection"/><category term="windows phone"/><category term="fluent api"/><category term="iis"/><category term="karmacracy"/><category term="mysql"/><category term="opinion"/><category term="sql server"/><category term="t-sql"/><category term="test"/><title type='text'>Diario de un desarrollador</title><subtitle type='html'>Diario de un desarrollador al que también le gusta correr en sus ratos libres...</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>72</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-2868751085549780830</id><published>2015-06-25T19:47:00.005+01:00</published><updated>2015-06-25T19:47:39.328+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="nodejs"/><category scheme="http://www.blogger.com/atom/ns#" term="npm"/><title type='text'>Update node in Mac OS X with npm</title><content type='html'>You can update node easily using npm following the next steps&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;console&quot; name=&quot;code&quot;&gt;sudo npm cache clean -f
sudo npm install -g n
sudo n stable&lt;/pre&gt;
&lt;br /&gt;
Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/2868751085549780830/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2015/06/update-node-in-mac-os-x-with-npm.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/2868751085549780830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/2868751085549780830'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2015/06/update-node-in-mac-os-x-with-npm.html' title='Update node in Mac OS X with npm'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-2989851678424542228</id><published>2015-06-25T19:46:00.000+01:00</published><updated>2015-06-25T19:48:22.373+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="nodejs"/><category scheme="http://www.blogger.com/atom/ns#" term="npm"/><title type='text'>Actualizar node en Mac OS X con npm</title><content type='html'>Puedes actualizar node fácilmente usando npm siguiendo los pasos siguientes&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;console&quot; name=&quot;code&quot;&gt;sudo npm cache clean -f
sudo npm install -g n
sudo n stable&lt;/pre&gt;
&lt;br /&gt;
Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/2989851678424542228/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2015/06/actualizar-node-en-mac-os-x-con-npm.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/2989851678424542228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/2989851678424542228'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2015/06/actualizar-node-en-mac-os-x-con-npm.html' title='Actualizar node en Mac OS X con npm'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-7758874637230501508</id><published>2013-03-07T07:03:00.000+00:00</published><updated>2013-03-07T07:03:02.519+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="css"/><category scheme="http://www.blogger.com/atom/ns#" term="html5"/><title type='text'>HTML5: Selectores CSS 2</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijOYBswMbEbBNVzyTZkl1jZOjF2a20CKMjIH6bIxvaOFoYUlP-xem0DWsewl9E-ztaQvI-_55ClMLYa-q6iPsu4yI1BN9BktVsNPwcPThmlLBJ8jgac6zXqo1mOgwEHBGVNu6rV0jpLoo/s1600/CSS3.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;150&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijOYBswMbEbBNVzyTZkl1jZOjF2a20CKMjIH6bIxvaOFoYUlP-xem0DWsewl9E-ztaQvI-_55ClMLYa-q6iPsu4yI1BN9BktVsNPwcPThmlLBJ8jgac6zXqo1mOgwEHBGVNu6rV0jpLoo/s200/CSS3.jpg&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
En la anterior &lt;a href=&quot;http://smarrerof.blogspot.com.es/2013/02/html5-selectores-css-1.html&quot; target=&quot;_blank&quot;&gt;entrada&lt;/a&gt; vimos una introducción a los &lt;b&gt;selectores CSS&lt;/b&gt; y en ella vimos algunos selectores que se introducen con la especificación de &lt;b&gt;HTML5&lt;/b&gt;. En esta entrada vamos a ver otro tipo de selectores, los denominados &lt;b&gt;pseudo-clases&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
En este artículo seguiremos usando el mismo ejemplo que usamos en la entrada anterior y que tiene el siguiente aspecto:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;&amp;lt;h1&amp;gt;Titulo&amp;lt;/h1&amp;gt;
&amp;lt;h2&amp;gt;Subtitulo&amp;lt;/h2&amp;gt;
&amp;lt;p id=&quot;p1&quot;&amp;gt;Esto es un parráfo y dentro hay un enlace a &amp;lt;a id=&quot;link1&quot; class=&quot;a1&quot; href=&quot;http://www.bing.com&quot;&amp;gt;Bing&amp;lt;/a&amp;gt; y otro a &amp;lt;a id=&quot;link2&quot; class=&quot;a1&quot; href=&quot;http://www.google.es&quot;&amp;gt;Google&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p id=&quot;p2&quot;&amp;gt;Tambien podemos tener un listado de idiomas&amp;lt;/p&amp;gt;
&amp;lt;ul id=&quot;list1&quot;&amp;gt;
    &amp;lt;li&amp;gt;Inglés&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Español&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Frances&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Alemán&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Italiano&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/pre&gt;
&lt;b&gt;:root&lt;/b&gt;&lt;br /&gt;
Personalmente desconocía este selector. Este selector selecciona el elemento&amp;nbsp;raíz&amp;nbsp;de un documento. Es un selector muy poco útil ya que siempre devuelve el elemento html y se incluye como novedad dentro de la&amp;nbsp;especificación&amp;nbsp;de HTML5.&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;:root { color: #FF0000 }&lt;/pre&gt;
&lt;b&gt;Selectores de hijos (child selectors)&lt;/b&gt;&lt;br /&gt;
Este selector nos ayuda a seleccionar un elemento individual que está contenido dentro de otro elemento. Podemos usar cuatro tipos de selectores&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;:fist-child: Selecciona el primer elemento de la lista de elementos.&lt;/li&gt;
&lt;li&gt;:last-child: Selecciona el último&amp;nbsp;elemento de la lista de elementos.&lt;/li&gt;
&lt;li&gt;:only-child: Selecciona el elemento si es el único en la lista de elementos.&lt;/li&gt;
&lt;li&gt;:only-of-type: Selecciona el elemento si es el único elemento en a lista y es de un tipo determinado.&lt;/li&gt;
&lt;/ul&gt;
Los tres últimos elementos (:last-child, :only-child y :only-of-type) son novedades&amp;nbsp;de la especificación de CSS3.&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;ul :first-child { color: #aaddcc }
ul :last-child { color: #336699 }&lt;/pre&gt;
Con este CSS estamos cambiando el estilo del primer y último descendiente de nuestro ul.
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaJbIzk8x2sql5G_N7hzy-JTedw-nS87zo2FagC-9gaiciSpPv9qEG8hyphenhyphenJttdHZ05PU6Akiic55XBYBq4MW-zEhvNxQdTTbEQjOShEHJdx5uVo86kjvwUfrmnd6mTZxbarr5iAgObMePU/s1600/test11.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;236&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaJbIzk8x2sql5G_N7hzy-JTedw-nS87zo2FagC-9gaiciSpPv9qEG8hyphenhyphenJttdHZ05PU6Akiic55XBYBq4MW-zEhvNxQdTTbEQjOShEHJdx5uVo86kjvwUfrmnd6mTZxbarr5iAgObMePU/s320/test11.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Selectores por posición (nth-child selectors)&lt;br /&gt;
Estos selectores son parecidos a los explicados anteriormente, pero se aplican en base al índice de su posición. Tenemos estos cuatro selectores&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;:nth-child(n): Selecciona el elemento que está en a&amp;nbsp;posición&amp;nbsp;n de la lista de elementos.&lt;/li&gt;
&lt;li&gt;:nth-last-child(n): Selecciona el elemento que está en la posición n desde el último elemento de la lista de&amp;nbsp;elementos.&lt;/li&gt;
&lt;li&gt;nth-of-type(n): Selecciona el elemento que está en la posición n de la lista elemento, en base al tipo definido por su padre.&lt;/li&gt;
&lt;li&gt;nth-last-of-type(n): Igual que el&amp;nbsp;anterior, pero el índice se cuenta desde el último elemento.&lt;/li&gt;
&lt;/ul&gt;
Todo estos&amp;nbsp;selectores&amp;nbsp;son nuevos y solo se&amp;nbsp;encuentran&amp;nbsp;disponibles en CSS3. En el siguiente ejemplo seleccionamos dentro de los hijos de ul el 2 elemento comenzando por el primer elemento y por el último.
&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;ul :nth-child(2) { color: #aaddcc }
ul :nth-last-child(2) { color: #336699 }&lt;/pre&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9m8dwwZmgH2Tq-XhGaTPOvTf6l01Ep1Q6dQA-Hp2Go2OYQFGBOXbk6KAJ3Fh2vJplhHalAElwV3EXkULz9Szd5TuD8zxqXAc9dyKQvV0Mc2alb3THU78Q0EUjDPyePLK3JJSDrRqFs_g/s1600/test12.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;236&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9m8dwwZmgH2Tq-XhGaTPOvTf6l01Ep1Q6dQA-Hp2Go2OYQFGBOXbk6KAJ3Fh2vJplhHalAElwV3EXkULz9Szd5TuD8zxqXAc9dyKQvV0Mc2alb3THU78Q0EUjDPyePLK3JJSDrRqFs_g/s320/test12.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;Selectores pseudo-clases&lt;/b&gt;&lt;br /&gt;
Los selectores de pseudo-clases no permiten seleccionar un elementos en base a su estado. Tenemos las siguiente pseudo-clases a nuestra disposición&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;:enabled - El selectores está habilitado.&lt;/li&gt;
&lt;li&gt;:disabled - El selector está deshabilitado.&lt;/li&gt;
&lt;li&gt;:checked - El selector está chequeado.&lt;/li&gt;
&lt;li&gt;:default - Selecciona valores por defecto.&lt;/li&gt;
&lt;li&gt;:valid e :invalid - Selecciona elementos de tipo input en base a si son validos o no (después de su valicación)&lt;/li&gt;
&lt;li&gt;:in-range y :out-of-range - Selecciona elementos dentro o fuera de un rango.&lt;/li&gt;
&lt;li&gt;:required y :optional - Selecciona elementos cuya presencia es obligatoria u opcional.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Todos estos selectores son introducidos en CSS3.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;b&gt;Selectores pseudo-clases dinámicos&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;:link y :visited - El selectores :link selecciona enlaces y el selector :visited selecciona aquellos enlaces que el usuario ya ha visitado.&lt;/li&gt;
&lt;li&gt;:hover: Este selector se usa cuando el ratón se mueve por encima de un elemento.&lt;/li&gt;
&lt;li&gt;:active: Este selector se usa cuando el usuario activa un elemento. Esto ocurre en la mayoría de los casos cuando el usuario hace click sobre el elemento.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Y con esto termina esta introducción a los selectores que tenemos disponibles en los CSS.&lt;br /&gt;
&lt;br /&gt;
Happy coding!&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/7758874637230501508/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2013/03/html5-selectores-css-2.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/7758874637230501508'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/7758874637230501508'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2013/03/html5-selectores-css-2.html' title='HTML5: Selectores CSS 2'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijOYBswMbEbBNVzyTZkl1jZOjF2a20CKMjIH6bIxvaOFoYUlP-xem0DWsewl9E-ztaQvI-_55ClMLYa-q6iPsu4yI1BN9BktVsNPwcPThmlLBJ8jgac6zXqo1mOgwEHBGVNu6rV0jpLoo/s72-c/CSS3.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-9015979083561907518</id><published>2013-02-19T06:58:00.001+00:00</published><updated>2013-02-21T07:04:35.757+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="css"/><category scheme="http://www.blogger.com/atom/ns#" term="html5"/><title type='text'>HTML5: Selectores CSS 1</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJgO7V7o783q3DzZK71EDW1vSLXEcmEbVCN-FdmQ9GUIutQ8SEoyWC0RQuEDaRGbaPm5X6ky9g9Vw5TaAw0Xr9FgedAtQsDqCxkcCrJarLBYr4GAmozbmK9F3aJ2NuH1MO9EwwDDZaqU4/s1600/CSS3.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;150&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJgO7V7o783q3DzZK71EDW1vSLXEcmEbVCN-FdmQ9GUIutQ8SEoyWC0RQuEDaRGbaPm5X6ky9g9Vw5TaAw0Xr9FgedAtQsDqCxkcCrJarLBYr4GAmozbmK9F3aJ2NuH1MO9EwwDDZaqU4/s200/CSS3.jpg&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Pese a la variedad de selectores que tenemos disponibles en los CSS en &lt;b&gt;HTML5&lt;/b&gt; se han añadido algunos más.&amp;nbsp;Aprovecharé&amp;nbsp;para repasar los más importantes y ver cuales son las principales novedades en esta nueva versión.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Para ver los selectores más comunes voy a usar esta página web de prueba
&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;&amp;lt;h1&amp;gt;Titulo&amp;lt;/h1&amp;gt;
&amp;lt;h2&amp;gt;Subtitulo&amp;lt;/h2&amp;gt;
&amp;lt;p id=&quot;p1&quot;&amp;gt;Esto es un parráfo y dentro hay un enlace a &amp;lt;a id=&quot;link1&quot; class=&quot;a1&quot; href=&quot;http://www.bing.com&quot;&amp;gt;Bing&amp;lt;/a&amp;gt; y otro a &amp;lt;a id=&quot;link2&quot; class=&quot;a1&quot; href=&quot;http://www.google.es&quot;&amp;gt;Google&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p id=&quot;p2&quot;&amp;gt;Tambien podemos tener un listado de idiomas&amp;lt;/p&amp;gt;
&amp;lt;ul id=&quot;list1&quot;&amp;gt;
    &amp;lt;li&amp;gt;Inglés&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Español&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Frances&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Alemán&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Italiano&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/pre&gt;
El aspecto que tiene este ejemplo en Google Chrome (tengamos en cuenta que cada navegador aplica unos estilos por defecto, por lo que este ejemplo se puede ver de diferente manera según el navegador que estemos usando).&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZA1y5UXD6UXmZoBu_ZpEqv7ekblp6UWlYGY0pZK9uwIJ0D-SOG7HAcCkSlW6CD5YNAs3wEmzNEo8-BgrjqHyyF-pcyz6SY13_bV2TAWaOcCd-7YV1yrk8bvScVkJX11ZaeUDFMoeAF6k/s1600/test-01.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;239&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZA1y5UXD6UXmZoBu_ZpEqv7ekblp6UWlYGY0pZK9uwIJ0D-SOG7HAcCkSlW6CD5YNAs3wEmzNEo8-BgrjqHyyF-pcyz6SY13_bV2TAWaOcCd-7YV1yrk8bvScVkJX11ZaeUDFMoeAF6k/s320/test-01.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;Selector universal&lt;/b&gt;&lt;br /&gt;
Se aplica sobre todo los elementos del documento, y donde se utiliza el * como selector. Por ejemplo&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;* { color: #008080; }&lt;/pre&gt;
Cambiaría el color de todos los elementos de nuestra página. El resultado es el siguiente&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6ZRO-UyAYnwTSibhNkEkYxGy7KO3047lGPRr7sUIbLCS4PNU-VLIITIaX9kayVDnT3lb9Jb3CSExYbvz7d-f6IZi9Y1Fw4gjWqrAzMxbAq_HJ3vJX2rWtAYYvbZZ27Zvx4BfjrgR6_Hs/s1600/test-02.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;234&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6ZRO-UyAYnwTSibhNkEkYxGy7KO3047lGPRr7sUIbLCS4PNU-VLIITIaX9kayVDnT3lb9Jb3CSExYbvz7d-f6IZi9Y1Fw4gjWqrAzMxbAq_HJ3vJX2rWtAYYvbZZ27Zvx4BfjrgR6_Hs/s320/test-02.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Un ejemplo más práctico relacionado con este selector está relacionado con los estilos que traen por defecto los navegadores. Cada navegador define un margin y un padding por defecto para cada elemento de nuestra página. Esto puede dar algún que otro quebradero de cabeza a la hora de maquetar nuestra página, así que buena costumbre es resetear los estilos por defecto. Una versión simplificada de esto podría ser lo siguiente (haciendo referencia al margin y el padding).&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;* { margin: 0; padding: 0 }&lt;/pre&gt;
Con esto nuestra página tendría el siguiente aspecto&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3lkxnWnV1m40Dd_SIn_OtYOYqgpaTi1SVEwflWp8Gn7xuICrWcFq_m5fw2QJ_Xx4c_5Bhw0z05cQd50vwXoOtdtHSo05bJGjtPsnc6OeflO3w_IH6sW5uwKMlDdsCWVQO9125BtVBJBE/s1600/test-03.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;159&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3lkxnWnV1m40Dd_SIn_OtYOYqgpaTi1SVEwflWp8Gn7xuICrWcFq_m5fw2QJ_Xx4c_5Bhw0z05cQd50vwXoOtdtHSo05bJGjtPsnc6OeflO3w_IH6sW5uwKMlDdsCWVQO9125BtVBJBE/s320/test-03.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;Selector por tipo&lt;/b&gt;&lt;br /&gt;
Mediante este selector podemos cambiar el estilo de un elemento (en base a su tipo) de nuestra página sin afectar a los demás. Por ejemplo, podemos&amp;nbsp;cambiar el color color de nuestros enlaces o de los textos de nuestros párrafos. En nuestro caso vamos cambiar el color de todos los&amp;nbsp;idiomas.&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;li { color: #00bfff; }&lt;/pre&gt;
Y nuestra página tendría el siguiente aspecto&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW7D2BiJ_iltKaIsqQ2YNw1oHpJhEdBlUNYzmT2P6kFYyScW7LmJYXJsG3tMpULJ4PTqZOGz-OIyl5syqmqNi8axcIzckWXq67ChQjDZCKa0nzbongXEQB8j94Fu-ox0IuZjhDnsW_lYQ/s1600/test-04.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW7D2BiJ_iltKaIsqQ2YNw1oHpJhEdBlUNYzmT2P6kFYyScW7LmJYXJsG3tMpULJ4PTqZOGz-OIyl5syqmqNi8axcIzckWXq67ChQjDZCKa0nzbongXEQB8j94Fu-ox0IuZjhDnsW_lYQ/s320/test-04.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;Selector por clase o identificador&lt;/b&gt;&lt;br /&gt;
Puede que no queramos aplicar el mismo estilo a todos los elementos del mismo tipo. Para eso podemos seleccionar el o los elementos a los que aplicar el estilo en base a la clase (especificada mediante el atributo class) o en base a su identificador (especificado&amp;nbsp;mediante&amp;nbsp;el atributo id).&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;.a1 { color: red; }
#p2 { color: greenyellow; }&lt;/pre&gt;
En este caso estamos cambiado el color de los elementos con la clase a1 y el idenficador p2. Podríamos afinar más combinando el selector de tipo y el de clase (o el de id). La forma de hacerlo sería la siguiente&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;a.a1 { color: red; } 
p#p2 { color: greenyellow; }&lt;/pre&gt;
Obteniendo el mismo resultado en ambos ejemplos&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3UhlfU0l7PfuL6jk2KdHRYxdX3fOn3logCTiq7QA1cGwQ7l92eaQ9u1UBIHsuw4pz6lJCRsibZRS2_96ouKWDXtS0Jmb1E2TPOrVAiZPt4Ehsb0XViz7QmELe8liQuOscb6WYrWEo1D0/s1600/test-05.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;238&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3UhlfU0l7PfuL6jk2KdHRYxdX3fOn3logCTiq7QA1cGwQ7l92eaQ9u1UBIHsuw4pz6lJCRsibZRS2_96ouKWDXtS0Jmb1E2TPOrVAiZPt4Ehsb0XViz7QmELe8liQuOscb6WYrWEo1D0/s320/test-05.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;Selector por atributo&lt;/b&gt;&lt;br /&gt;
Podemos también seleccionar los&amp;nbsp;elementos&amp;nbsp;en base a si tiene un atributo o incluso si ese atributo tiene un valor determinado. Por ejemplo podemos seleccionar aquellos enlaces que tengan el atributo href definir (todos en nuestro caso)&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;[href] { color: #8b0000; }&lt;/pre&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgekirMwFJsSc841RYRv8maFRFwA2bREO8G_t1pW4_vgVhForOTv4t_VVax6W5o88CwBjYOAigP8mj8a38buGBuNL3xW7Nzu_x20zluRtHykPhQgG56YXau0OBuQNZeWLVnfAcyDXkS_K0/s1600/test-06.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;239&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgekirMwFJsSc841RYRv8maFRFwA2bREO8G_t1pW4_vgVhForOTv4t_VVax6W5o88CwBjYOAigP8mj8a38buGBuNL3xW7Nzu_x20zluRtHykPhQgG56YXau0OBuQNZeWLVnfAcyDXkS_K0/s320/test-06.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
En los condicionales que podemos usar con este selector encontramos la primera novedad en CSS3. Creo que el siguiente listado queda todo más claro.&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;[attr]: Selecciona un elemento si contiene el atributo attr&amp;nbsp;independientemente&amp;nbsp;el valor que tenga.&lt;/li&gt;
&lt;li&gt;[attr=&quot;val&quot;]: Selecciona un elemento si contiene el atributo attr y cuyo valor es val.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;[attr^=&quot;val&quot;]: Selecciona un elemento si contiene el atributo attr y cuyo valor comienza por val.&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;[attr$=&quot;val&quot;]: Selecciona un elemento si contiene el atributo attr y cuyo valor termina por val.&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;[attr*=&quot;val&quot;]: Selecciona un elemento si contiene el atributo attr y cuyo valor contiene el valor val.&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;[attr~=&quot;val&quot;]: Selecciona un elemento si contiene el atributo attr y cuyo valor contiene varios valores pero uno es val.&lt;/li&gt;
&lt;li&gt;[attr|=&quot;val&quot;]: Selecciona un elemento si contiene el atributo attr y cuyo valor contiene una lista de valores separados por el&amp;nbsp;carácter&amp;nbsp;- y cuyo primer valor es val.&lt;/li&gt;
&lt;/ul&gt;
Los elementos en cursiva son las novedades introducidas en HTML5. Viendo un ejemplo de uno de ellos, podríamos seleccionar aquellos elementos que tuvieran una clase que empezara por a&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;[class^=&quot;a&quot;] { color: #228b22; }&lt;/pre&gt;
&lt;b&gt;Combinando selectores&lt;/b&gt;&lt;br /&gt;
Si queremos aplicar el mismo estilo en varios selectores podemos hacerlo de la siguiente manera&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;a, li { color: #228b22; }&lt;/pre&gt;
De esta forma estamos aplicando el mismo estilo a todos los enlaces y elementos de la lista.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhccBADBrrAlFa9hjKQqCNyu2dolvjFSex-_SeT44-I12SJ10ISw2esLXaKeSwiFnirBwCYQ3oLsNTb4CxygoMWqFWVSlIzX2kTlMvLHIxEvFDPh51js-K2lpZCUMvXI61WggcpKNDp0u8/s1600/test-07.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;230&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhccBADBrrAlFa9hjKQqCNyu2dolvjFSex-_SeT44-I12SJ10ISw2esLXaKeSwiFnirBwCYQ3oLsNTb4CxygoMWqFWVSlIzX2kTlMvLHIxEvFDPh51js-K2lpZCUMvXI61WggcpKNDp0u8/s320/test-07.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;Descendientes&lt;/b&gt;&lt;br /&gt;
También podemos seleccionar elementos en base a su padre. Podemos seleccionar descendientes de primer nivel o de cualquier nivel inferior. La forma hacerlo es la siguiente de seleccionar cualquier descendiente es la siguiente&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;p a { color: #00ced1; }&lt;/pre&gt;
Y la forma de seleccionar solo los descendiente directos se hace de la siguiente forma&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;p &amp;gt; a { color: #00ced1; }&lt;/pre&gt;
En ambos ejemplos estamos seleccionando los enlaces que sean descendientes de un&amp;nbsp;párrafo.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_zBSpEXmiIfHmSPIqAs7foDkAbfNuKHj4dk12RzJ3nTYh3LDkMdrw38hMjQXoeJcIKHdBbV3Oedy2TvG8BVv-tJx40XwAfOFOtCriZVq0lBc05Id66wRlvf_pApHGrXPNzPKEb_Gp-Oo/s1600/test-08.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;238&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_zBSpEXmiIfHmSPIqAs7foDkAbfNuKHj4dk12RzJ3nTYh3LDkMdrw38hMjQXoeJcIKHdBbV3Oedy2TvG8BVv-tJx40XwAfOFOtCriZVq0lBc05Id66wRlvf_pApHGrXPNzPKEb_Gp-Oo/s320/test-08.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;Sibling&lt;/b&gt;&lt;br /&gt;
Otro selector que tenemos a nuestro alcance es el selector de sibling (selector de hermanos). Esto nos permite seleccionar uno o varios elementos en base a otro elemento que se encuentra a su mismo nivel.&lt;br /&gt;
Por ejemplo en este caso&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;h2 + p { color: #2f4f4f; }&lt;/pre&gt;
Estamos seleccionado los&amp;nbsp;párrafos&amp;nbsp;que se encuentren inmediatamente después de un h2.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6UGgmWg83iqj9hqmyY_SDvy_CyFRT1t9BtIV06rLzO3DvNvMbPu1vud0odEWA-P6A6RXLfOeYxVfeTGhr2w9lZEOsYr_yF4Xad68-3Fj6bzJZPF4yZqJWrD_3lIL3wpf6FfoPwnVFIcc/s1600/test-09.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;237&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6UGgmWg83iqj9hqmyY_SDvy_CyFRT1t9BtIV06rLzO3DvNvMbPu1vud0odEWA-P6A6RXLfOeYxVfeTGhr2w9lZEOsYr_yF4Xad68-3Fj6bzJZPF4yZqJWrD_3lIL3wpf6FfoPwnVFIcc/s320/test-09.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
En este otro caso estamos seleccionado todos los párrafos que se encuentren después de un h2, inmediatamente después o no (&lt;i&gt;este selector también ha sido introducido en la especificación de HTML5&lt;/i&gt;)&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;h2 ~ p { color: #2f4f4f; }&lt;/pre&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggrBMMwkyaDzzJgiSQ2Xh65AltTw6xCxhnxh7m0Q5ZVY_NyGqc02dxp7RIJztUUzzyqwvEAYCX_9tnsoEulMFQYOsDW1atHp-RjMCrjpz9Gw93pgSU0Xtw29SOn0UHUymCp6FYz2HNZYM/s1600/test-10.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;246&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggrBMMwkyaDzzJgiSQ2Xh65AltTw6xCxhnxh7m0Q5ZVY_NyGqc02dxp7RIJztUUzzyqwvEAYCX_9tnsoEulMFQYOsDW1atHp-RjMCrjpz9Gw93pgSU0Xtw29SOn0UHUymCp6FYz2HNZYM/s320/test-10.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Y con esto termina esta introducción a los selectores que tenemos disponibles en los CSS. Para la próxima entrada dejaremos los selectores denominados pseudo clases que también son bastante útiles a la hora de hacer nuestros estilos.&lt;br /&gt;
&lt;br /&gt;
Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/9015979083561907518/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2013/02/html5-selectores-css-1.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/9015979083561907518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/9015979083561907518'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2013/02/html5-selectores-css-1.html' title='HTML5: Selectores CSS 1'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJgO7V7o783q3DzZK71EDW1vSLXEcmEbVCN-FdmQ9GUIutQ8SEoyWC0RQuEDaRGbaPm5X6ky9g9Vw5TaAw0Xr9FgedAtQsDqCxkcCrJarLBYr4GAmozbmK9F3aJ2NuH1MO9EwwDDZaqU4/s72-c/CSS3.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-4685711843039227617</id><published>2013-02-15T06:59:00.001+00:00</published><updated>2013-02-15T07:00:39.069+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="html5"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><title type='text'>HTML5: Introducción a los Web Workers 2</title><content type='html'>En la &lt;a href=&quot;http://smarrerof.blogspot.com.es/2013/02/html5-introduccion-los-web-workers-1.html&quot; target=&quot;_blank&quot;&gt;entrada anterior&lt;/a&gt; vimos una introducción a los &lt;b&gt;web workers&lt;/b&gt;. En ella vimos como crearlos y como comunicarnos desde la página web con el web worker y viceversa. Pese a que con lo visto puede ser más que suficiente en&amp;nbsp;muchísimos&amp;nbsp;casos se nos&amp;nbsp;quedaron&amp;nbsp;algunas cosas en el aire y que veremos a continuación.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Gestión de errores&lt;/b&gt;&lt;br /&gt;
Puede que para algunos procesos simples no nos tengamos que preocupar de la gestión de errores (aunque creo que nunca está de más), pero en otras ocasiones puede que se imprescindible. Para comunicar un error desde nuestro worker usaremos el &lt;b&gt;evento error&lt;/b&gt;, así que lo que haremos será suscribirnos al evento error del worker desde nuestra página web.&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;worker.addEventListener(&#39;error&#39;, _error, false);

function _error(e) {
    var output = document.querySelector(&#39;#output&#39;);
    output.innerHTML = &#39;ERROR: Line &#39; + e.lineno + &#39; in &#39; + e.filename + &#39;: &#39; + e.message;
}&lt;/pre&gt;
Y en el worker usaremos el siguiente código para simular un error (lanzaremos un error en caso que el número pasado sea cero)&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;// Procesamos el mensaje recibido
function _message(e) {
    // Simulamos un error
    if (e.data == 0)
        throw new Error(0, &quot;Por favor, introduce un número mayor o igual a uno&quot;);

    var primes = _getPrimes(e.data);
    self.postMessage(primes);
}&lt;/pre&gt;
&lt;b&gt;Detener el web worker&lt;/b&gt;&lt;br /&gt;
En el caso que queramos detener un worker, lo podemos hacer de dos maneras. La primera de ellas desde el código del propio worker. En ese caso debemos usar el &lt;b&gt;método close&lt;/b&gt;. Para probar esté método pondremos el siguiente código en el método _message de nuestro worker (finalizamos la ejecución del worker en caso que intentemos calcular los números primos de un número negativo).&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;// Simulamos la detención del worker
if (e.data &amp;lt; 0) 
    self.close();    &lt;/pre&gt;
En caso que queramos acabar con el worker desde la página web debemos usar el &lt;b&gt;método terminate&lt;/b&gt;. En nuestro ejemplo usaremos un botón para detener la ejecución del worker&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;&amp;lt;input type=&quot;button&quot; id=&quot;btnTerminate&quot; value=&quot;Terminar&quot; onclick=&quot;_terminate()&quot;/&amp;gt;&lt;/pre&gt;
Y este es el código del método onclick&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;function _terminate() {
    worker.terminate();
}&lt;/pre&gt;
Y con esto acabamos la introducción básica a los web workers. Espero que les sea de utilidad.&lt;br /&gt;
&lt;br /&gt;
Happy coding!
</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/4685711843039227617/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2013/02/html5-introduccion-los-web-workers-2.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/4685711843039227617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/4685711843039227617'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2013/02/html5-introduccion-los-web-workers-2.html' title='HTML5: Introducción a los Web Workers 2'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-8788907538028460278</id><published>2013-02-07T18:08:00.003+00:00</published><updated>2013-02-08T08:15:25.695+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="html5"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><title type='text'>HTML5: Introducción a los Web Workers 1</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpIVu3tvGUZ-4poM0wH8P6CJWHTmSAGarplYSqq3pheMFyphfSpzBo-Zrkc-eYvTL1HKTSWGmo971stD2QMrnBoZXlftjFPiZZuejXa_2iDEmPhB9rrCY6ipeCtaDIqJB5VOSwHHg4CDQ/s1600/webworkers.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpIVu3tvGUZ-4poM0wH8P6CJWHTmSAGarplYSqq3pheMFyphfSpzBo-Zrkc-eYvTL1HKTSWGmo971stD2QMrnBoZXlftjFPiZZuejXa_2iDEmPhB9rrCY6ipeCtaDIqJB5VOSwHHg4CDQ/s1600/webworkers.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Uno de los mayores&amp;nbsp;inconvenientes&amp;nbsp;que tiene javascript como&amp;nbsp;lenguaje&amp;nbsp;de programación es que es un &lt;b&gt;entorno de subproceso único&lt;/b&gt;. Esto implica que en procesos largos y costosos podemos dejar &quot;congelado&quot; el navegador del cliente.&lt;br /&gt;
Supongamos la siguiente página&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; div=&quot;&quot; name=&quot;code&quot;&gt;&amp;lt;input id=&quot;txtValue&quot; type=&quot;text&quot; /&amp;gt;&amp;lt;input id=&quot;btnProcess&quot; onclick=&quot;_process()&quot; type=&quot;button&quot; value=&quot;Calculate primes&quot; /&amp;gt;&amp;lt;div id=&quot;output&quot;&amp;gt;&lt;/pre&gt;
Y el siguiente código en javascript&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;function _process() {
    var value = document.querySelector(&#39;#txtValue&#39;).value;
    var primes = getPrimes(value);

    var output = document.querySelector(&#39;#output&#39;);
    output.innerHTML = primes.toString();
}

// Devuelve un array con los números primos comprendidos entre 1 y value.
function getPrimes(value) {
    var primes = [];
            
    for (var i = 1; i &amp;lt;= value; i++) {
        if (_isPrime(i))
            primes.push(i);                
    }

    return primes;
}

// Devuelve true si un número es primo, false en otro caso.
function isPrime(n) {
    if (n &amp;lt; 2) return false;
    var m = Math.sqrt(n);
    for (var i = 2; i &amp;lt;= m; i++)
        if (n % i == 0) return false;
    return true;
}&lt;/pre&gt;
Si ponemos un valor elevado, por ejemplo un millón, vemos que durante un par de segundos nuestra página deja de responder.&lt;br /&gt;
&lt;br /&gt;
Los &lt;b&gt;Web Workers aparecen con la especificación de HTML5&lt;/b&gt; y se definen como un script que se ejecuta en background independientemente de otros scripts y&amp;nbsp;&lt;b&gt;sin que afecte al rendimiento de la página&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Modificar el comportamiento del ejemplo anterior para que se ejecute en un Web Worker es bastante sencillo. La forma más fácil de hacer es aislar el código de nuestro Web Worker en un fichero y crear a partir de él nuestro&amp;nbsp;objeto &lt;b&gt;Worker&lt;/b&gt;. Para hacer esto haremos lo siguiente en nuestra página web&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;var worker = new Worker(&#39;webworker.js&#39;);
worker.addEventListener(&#39;message&#39;, _message, false);

function _message(e) {
    var output = document.querySelector(&#39;#output&#39;);
    output.innerHTML = e.data.toString();
}&lt;/pre&gt;
En la primera linea creamos nuestro Worker a partir del código que tengamos en el fichero webworker.js, y en la segunda linea nos &quot;enganchamos&quot; al&amp;nbsp;&lt;b&gt;evento&amp;nbsp;message del Worker&lt;/b&gt;, ya que a través de este evento es como se comunicará nuestro Worker con nosotros (la página web). Sólo nos falta saber como nos comunicaremos con nuestro Worker. Esto también es bastante sencillo y lo haremos de la siguiente manera&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;function _process() {           
    var value = document.querySelector(&#39;#txtValue&#39;).value;
    worker.postMessage(value);
}&lt;/pre&gt;
Este método será llamado cada vez que pulsemos el botón &quot;Calculate primes&quot;. En el extraemos el valor que queremos procesar y lo pasamos como&amp;nbsp;parámetro&amp;nbsp;en el método &lt;b&gt;postMessage&lt;/b&gt;. Este método es la forma que tenemos de&amp;nbsp;comunicarnos&amp;nbsp;con el Worker.&lt;br /&gt;
&lt;br /&gt;
Construir el Worker también es bastante fácil y en él se aplican los mismo métodos y eventos que hemos comentado anteriormente. El Worker recibe la información de la página a través del evento message y se comunicará con la página a través del método postMessage. Sabiendo esto el código del Worker quedaría de la siguiente forma&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;addEventListener(&#39;message&#39;, _message, false);

// Procesamos el mensaje recibido
function _message(e) {
    var primes = _getPrimes(e.data);
    self.postMessage(primes);
}

// Devuelve un array con los números primos comprendidos entre 1 y value.
function _getPrimes(value) {
    var primes = [];

    for (var i = 1; i &amp;lt;= value; i++) {
        if (_isPrime(i))
            primes.push(i);
    }

    return primes;
}

// Devuelve true si un número es primo, false en otro caso.
function _isPrime(n) {
    if (n &amp;lt; 2) return false;
    var m = Math.sqrt(n);
    for (var i = 2; i &amp;lt;= m; i++)
        if (n % i == 0) return false;
    return true;
}&lt;/pre&gt;
Si ejecutamos este código con valores elevados, vemos que nuestra página no sufre&amp;nbsp;ningún&amp;nbsp;tipo de efecto secundario mejorando considerablemente la experiencia del usuario en la misma.&lt;br /&gt;
&lt;br /&gt;
Otra cuestion a tener en cuenta en los Web Workers es a que tienen y a que no tienen acceso (por cuestiones de seguridad). Bien, los Web Wokers puede acceder a&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Objeto navigator&lt;/li&gt;
&lt;li&gt;Objeto location (de solo lectura)&lt;/li&gt;
&lt;li&gt;XMLHttpRequest&lt;/li&gt;
&lt;li&gt;setTimeout()/clearTimeout() y setInterval()/clearInterval()&lt;/li&gt;
&lt;li&gt;Caché de la aplicación&lt;/li&gt;
&lt;li&gt;Importación de secuencias de comandos externas a través del método importScripts()&lt;/li&gt;
&lt;li&gt;Generación de otros Web Workers&lt;/li&gt;
&lt;/ul&gt;
Y no pueden acceder&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;DOM (no es seguro para el subproceso)&lt;/li&gt;
&lt;li&gt;Objeto window&lt;/li&gt;
&lt;li&gt;Objeto document&lt;/li&gt;
&lt;li&gt;Objeto parent&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Respecto a los navegadores compatibles, con IE solo podremos usar esta característica de HTML5 a partir de la versión 10. Para el resto de navegadores lo mejor es mirar en esta &lt;a href=&quot;http://caniuse.com/#search=worker&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;página&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Más información en la página de &lt;a href=&quot;http://www.w3schools.com/html/html5_webworkers.asp&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;w3schools&lt;/a&gt;&amp;nbsp;&lt;/div&gt;
&lt;br /&gt;
EDIT: Por recomendación &lt;a href=&quot;https://twitter.com/ydarias/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;@ydarias&lt;/a&gt;, añado la página&amp;nbsp;de &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Mozilla&lt;/a&gt; sobre el uso de los web workers como lectura recomendada.&lt;br /&gt;
&lt;br /&gt;
También se puede bajar el ejemplo que hemos comentado desde &lt;a href=&quot;http://sdrv.ms/VK2DHj&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;aquí&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Happy coding!
</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/8788907538028460278/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2013/02/html5-introduccion-los-web-workers-1.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/8788907538028460278'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/8788907538028460278'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2013/02/html5-introduccion-los-web-workers-1.html' title='HTML5: Introducción a los Web Workers 1'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpIVu3tvGUZ-4poM0wH8P6CJWHTmSAGarplYSqq3pheMFyphfSpzBo-Zrkc-eYvTL1HKTSWGmo971stD2QMrnBoZXlftjFPiZZuejXa_2iDEmPhB9rrCY6ipeCtaDIqJB5VOSwHHg4CDQ/s72-c/webworkers.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-6977008834102110265</id><published>2012-11-27T16:31:00.000+00:00</published><updated>2012-11-27T16:31:35.580+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="jQuery"/><title type='text'>Limpiar un input file con jQuery</title><content type='html'>Hace bastante tiempo que no escribo nada porque ando bastante liado, pero me ha parecido bastante interesante compartir esto. El problema surge cuando tras subir un fichero a nuestro servidor queremos limpiar el contenido de nuestro input file desde cliente (por ejemplo, con &lt;a href=&quot;http://jquery.com/&quot; target=&quot;_blank&quot;&gt;jQuery&lt;/a&gt;). La primera aproximación podría ser esta
&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;$(&#39;#fileupload&#39;).attr({ value: &#39;&#39; });&lt;/pre&gt;
Si hemos trabajado algo con web sabemos que esta opción no es válida porque por motivos de seguridad el control es de solo lectura y no podemos modificar su contenido. La solución pasa por volver a crear el control usando el método &lt;a href=&quot;http://api.jquery.com/clone/&quot; target=&quot;_blank&quot;&gt;clone&lt;/a&gt; de jQuery.&lt;br /&gt;
&lt;pre class=&quot;javascript&quot; name=&quot;code&quot;&gt;$fileupload = $(&#39;#fileupload&#39;);
$fileupload.replaceWith($fileupload.clone(true));&lt;/pre&gt;
El método clone admite dos parámetros que nos&amp;nbsp;permitirá&amp;nbsp;conservar los valores y los manejadores de los eventos que&amp;nbsp;tengamos&amp;nbsp;definidos en nuestro control o controles hijos.&lt;br /&gt;
&lt;br /&gt;
Espero que les sea útil. Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/6977008834102110265/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/11/limpiar-un-input-file-con-jquery.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/6977008834102110265'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/6977008834102110265'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/11/limpiar-un-input-file-con-jquery.html' title='Limpiar un input file con jQuery'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-6130759528834932145</id><published>2012-11-02T19:52:00.003+00:00</published><updated>2012-11-02T19:52:36.147+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="csharp"/><title type='text'>C# 5 - Caller Information</title><content type='html'>&lt;div&gt;
Una de las novedades que trae C# en su versión 5.0 es el &lt;b&gt;Caller Information&lt;/b&gt; que nos puede ser bastante útil para trazar nuestras aplicaciones. Ahora podemos obtener la siguiente información del método &quot;llamante&quot;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;CallerFilePathAttribute&lt;/b&gt;: Ruta completa del fichero que contiene al &quot;llamante&quot;. Hay que tener en cuenta que es la ruta en el momento de la compilación.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CallerLineNumberAttribute: &lt;/b&gt;Número de linea que contiene la llamada a nuestro método.&amp;nbsp;Line number in the
source file at which the method is called.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CallerMemberNameAttribute: &lt;/b&gt;Método o propiedad del &quot;llamante&quot;.&lt;/li&gt;
&lt;/ul&gt;
Y como siempre, lo mejor es verlo todo con un ejemplo.&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;private void button_Click(object sender, EventArgs e)
{
    //...
    NuestroMetodo();
    //...
}

public void NuestroMetodo([CallerFilePath] string sourceFile = &quot;&quot;,
    [CallerLineNumber] int lineNumer = 0,
    [CallerMemberName] string memberName = &quot;&quot;) {

    string msg = String.Format(&quot;{0}: Llamada a nuestro método desde {1}.{3}: line {2} en {4}&quot;,
        DateTime.Now.ToString(&quot;yyyy-mm-dd HH:MM:ss.fff&quot;),
        Path.GetFileNameWithoutExtension(sourceFile),
        lineNumer,
        memberName,
        sourceFile);

    Debug.WriteLine(msg);
}&lt;/pre&gt;
Y el resultado de ejecutar este código es el siguiente&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;2012-41-02 19:11:52.219: Llamada a nuestro método desde Form1.button_Click: line 25 en C:\Users\Sergio\Documents\Visual Studio 2012\Projects\CallerInformationDemo\CallerInformationDemo\Form1.cs&lt;/pre&gt;
Hay que tener en cuenta que los parámetros a los que le apliquemos los atributos deben ser opcionales. Si no lo hacemos así, el compilador de C# nos los requerirá en la llamada, y los valores que pasemos sobreescribiran los valores por defecto.&lt;br /&gt;
&lt;br /&gt;
No se hasta que punto es práctico decorar todos nuestro métodos con estos atributos pero&amp;nbsp;quizás&amp;nbsp;para determinados momentos nos pueda resultar útil guardar esta información para posteriormente analizarla.&lt;br /&gt;
&lt;br /&gt;
Happy coding!&lt;/div&gt;
&lt;br /&gt;
Más información sobre estos nuevos atributos en la &lt;a href=&quot;http://msdn.microsoft.com/es-es/ms348103.aspx&quot; target=&quot;_blank&quot;&gt;MSDN&lt;/a&gt;.&lt;br /&gt;
&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callerfilepathattribute(v=vs.110).aspx&quot; target=&quot;_blank&quot;&gt;CallerFilePathAttribute&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callerlinenumberattribute(v=vs.110).aspx&quot; target=&quot;_blank&quot;&gt;CallerLineNumberAttribute&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute(v=vs.110).aspx&quot; target=&quot;_blank&quot;&gt;CallerMemberNameAttribute&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/6130759528834932145/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/11/c-5-caller-information.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/6130759528834932145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/6130759528834932145'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/11/c-5-caller-information.html' title='C# 5 - Caller Information'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-5041833846245803544</id><published>2012-10-28T18:30:00.003+00:00</published><updated>2012-10-28T18:30:50.445+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="visual studio"/><title type='text'>Visual Studio 2012 - Cambiando el idioma del IDE</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimsL4TiYZ18yhHP-YWDYURo8nKYPXktm-qNulBEb1OyN3oN-z_5RDTvlL5imsoAHrbtPIkEiYg7q3nH_Mck-C79TesRifzjk2fS8MygoSAQbF8s9rOLJ7uW6Xmn0gSlekdvnDqdvawWSg/s1600/visual-studio-2012.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;200&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimsL4TiYZ18yhHP-YWDYURo8nKYPXktm-qNulBEb1OyN3oN-z_5RDTvlL5imsoAHrbtPIkEiYg7q3nH_Mck-C79TesRifzjk2fS8MygoSAQbF8s9rOLJ7uW6Xmn0gSlekdvnDqdvawWSg/s200/visual-studio-2012.jpg&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Para bien o para mal me he acostumbrado a utilizar el &lt;a href=&quot;http://msdn.microsoft.com/es-es/vstudio/aa718325.aspx&quot; target=&quot;_blank&quot;&gt;Visual Studio&lt;/a&gt; en inglés, así que cuando en la versión 2012 solo tenía acceso a la versión española me he sentido un poco perdido a la hora de navegar por los&amp;nbsp;menús&amp;nbsp;y demás opciones del IDE, menos mal que los atajos de teclado son los mismos.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Para cambiar el idioma del IDE&lt;/b&gt; tan sólo debemos descargar el&amp;nbsp;&lt;a href=&quot;http://www.microsoft.com/en-us/download/details.aspx?id=30681&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;Microsoft Visual Studio 2012 Language Pack&lt;/b&gt;&lt;/a&gt;&amp;nbsp;en el idioma que queramos tener (en nuestro caso ingés) y posteriormente instalarlo. Luego iremos a Herramientas &amp;gt; Opciones y dentro del árbol vamos a Entorno &amp;gt; Configuración internacional y en idioma seleccionamos Inglés. Para que los cambios tengan efecto tendremos que cerrar el volver a abrir el Visual Studio.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8iuviMUsrQTlrQhEb6EqO6zHmIjR3lyoshF_HeGCkqoTSww1zyrVLwbXvRnybYdMZnstHc_uFyDOQascK2COV1SQh2A8u4-bNEDlkfizD1zkZgB6KjuhXWOmGgHmN8GJCiSLunECEDu4/s1600/language-selector.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;178&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8iuviMUsrQTlrQhEb6EqO6zHmIjR3lyoshF_HeGCkqoTSww1zyrVLwbXvRnybYdMZnstHc_uFyDOQascK2COV1SQh2A8u4-bNEDlkfizD1zkZgB6KjuhXWOmGgHmN8GJCiSLunECEDu4/s320/language-selector.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Y así tenemos el antes&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2GfwYaal58KjHvLx4SLRhRdWwEDBOwj3nO9GrSUdAlp0dWYUfIxsnokzWl0tYA_zMFD5VtVAmK5QnvShbZbdm2jhtdKrMSVhAcixgUdfpDUFRxuyp3EjBljtwGAobi_vNtpzMAZKB-Do/s1600/visual-studio-esp.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;190&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2GfwYaal58KjHvLx4SLRhRdWwEDBOwj3nO9GrSUdAlp0dWYUfIxsnokzWl0tYA_zMFD5VtVAmK5QnvShbZbdm2jhtdKrMSVhAcixgUdfpDUFRxuyp3EjBljtwGAobi_vNtpzMAZKB-Do/s320/visual-studio-esp.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
y el después&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSIXFphm_3XUkzFqTQkO2M41SBbT-JHjfBLzXFgX6QVlEHh7QaPbdirqOIIwtb9YS-Z-5cU7_ffpBDtZRXrm_z3hyzp3_WTWFO_kuIJp3EseYimiYmxTsX0_w2G7MNBXBGVwN6Yqcxgns/s1600/visual-studio-enu.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;190&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSIXFphm_3XUkzFqTQkO2M41SBbT-JHjfBLzXFgX6QVlEHh7QaPbdirqOIIwtb9YS-Z-5cU7_ffpBDtZRXrm_z3hyzp3_WTWFO_kuIJp3EseYimiYmxTsX0_w2G7MNBXBGVwN6Yqcxgns/s320/visual-studio-enu.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Y asunto resuelto, ya tenemos nuestro Visual Studio en inglés.&lt;br /&gt;
&lt;br /&gt;
Happy coding!&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/5041833846245803544/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/10/visual-studio-2012-cambiando-el-idioma.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/5041833846245803544'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/5041833846245803544'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/10/visual-studio-2012-cambiando-el-idioma.html' title='Visual Studio 2012 - Cambiando el idioma del IDE'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimsL4TiYZ18yhHP-YWDYURo8nKYPXktm-qNulBEb1OyN3oN-z_5RDTvlL5imsoAHrbtPIkEiYg7q3nH_Mck-C79TesRifzjk2fS8MygoSAQbF8s9rOLJ7uW6Xmn0gSlekdvnDqdvawWSg/s72-c/visual-studio-2012.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-7060024856615419619</id><published>2012-10-27T08:06:00.001+01:00</published><updated>2012-10-27T08:08:01.517+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="general"/><title type='text'>Actualizando a Windows 8 Pro desde Windows 8 Release Preview</title><content type='html'>Desde ayer está disponible el nuevo &lt;b&gt;Windows 8 para todos los públicos&lt;/b&gt;. Pese a que desde hace tiempo estoy usando la &lt;b&gt;Release Preview&lt;/b&gt; ya era hora de&amp;nbsp;actualizar&amp;nbsp;el sistema, para entre otras cosas poder instalar el &lt;b&gt;Visual Studio 2012 Pro&lt;/b&gt; (versión definitiva). En el momento de realizar la actualización me surgieron dos dudas&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Desde la página web donde podías comprar la actualización no decía nada de que se pudiera actualizar desde las versiones &quot;betas&quot; de Windows 8. Sólo se podía actualizar desde Windows XP SP3, Windows Vista y Windows 7.&lt;/li&gt;
&lt;li&gt;Si compraba la actualización, ¿qué era lo que realmente estaba comprando?¿una iso?¿una&amp;nbsp;actualización&amp;nbsp; Y si mañana me compro un SSD y quiero hacer una instalación limpia, ¿puedo reinstalar mi Windows 8?&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
Con esta dudas lo primero que hice fue intentar acceder a la actualización a través de la propiedades del sistema. Pero tras varios intentos siempre obtenía el mismo error.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAiqGXgeAP0eHimnDBn2uv2O89od_yxVHZ32pK83stvI-6LEUwQli2uJRQE7FZhtzeHSgq2mh0xC2oef_nmAij01DIK5O9gJnvqRy-O7qkhLcQNkJ1J1SloRbNfdbB0TsW8R7fE1jQzSE/s1600/upgrade.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;63&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAiqGXgeAP0eHimnDBn2uv2O89od_yxVHZ32pK83stvI-6LEUwQli2uJRQE7FZhtzeHSgq2mh0xC2oef_nmAij01DIK5O9gJnvqRy-O7qkhLcQNkJ1J1SloRbNfdbB0TsW8R7fE1jQzSE/s400/upgrade.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
El siguiente pasó fue ir a la página de actualización y descargarme un ejecutable se encargaría del proceso de actualización. Así lo hice y de esta manera todo fue correcto. Nada más arrancar el &quot;actualizador&quot; éste se tomará su tiempo para analizar tu sistema actual e informarte de los problemas que puedes tener con la aplicaciones instaladas a la hora de actualizar tu sistema. En mi caso solo tendría problemas con el Daemon Tools Lite que uso para montar imágenes, o sea, un problema menor teniendo en cuenta que el Windows ya trae este comportamiento de serie. Tras esto podemos realizar la compra de la actualización&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkNinqbwCmmNMhMHe4uZeGi-Ye9c2c7UW2T84_gmuUPt4qr_zvchnxBnibwf6tJDx5sIyYo0-r57e6tIZiY9Pni6PJIEluyWNawp49TIz_uSD6V1XvHIpAX468I1X8CCoh8HoK3Ucptkg/s1600/compra.01.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;251&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkNinqbwCmmNMhMHe4uZeGi-Ye9c2c7UW2T84_gmuUPt4qr_zvchnxBnibwf6tJDx5sIyYo0-r57e6tIZiY9Pni6PJIEluyWNawp49TIz_uSD6V1XvHIpAX468I1X8CCoh8HoK3Ucptkg/s320/compra.01.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHfEZDSnPQ96sGQluCf-p-I63AqUBDcrKmAkcgxx3Ph4_e1Ua15Alpj6kwdA2qn-Zek0zEZ47hOSVs2JVIcOREcwns7h7jhZB0UIcLezjawOZOb5xnrmjiiyK4RatexRcHV_iBFaYYtC8/s1600/compra.02.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;251&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHfEZDSnPQ96sGQluCf-p-I63AqUBDcrKmAkcgxx3Ph4_e1Ua15Alpj6kwdA2qn-Zek0zEZ47hOSVs2JVIcOREcwns7h7jhZB0UIcLezjawOZOb5xnrmjiiyK4RatexRcHV_iBFaYYtC8/s320/compra.02.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvlownRh1vtGG6AeF9hWsQlyDWOUleh2B8Uxs8ddubCGlBrkclf5yRETULeKS7dzLBOYTdHhUigMvt2xKnzqawtHsXFIVwmODhzd6rxGnz0aNgsxmTlNoNdf_h5TlQtF1v110VSTclnnk/s1600/compra.03.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;250&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvlownRh1vtGG6AeF9hWsQlyDWOUleh2B8Uxs8ddubCGlBrkclf5yRETULeKS7dzLBOYTdHhUigMvt2xKnzqawtHsXFIVwmODhzd6rxGnz0aNgsxmTlNoNdf_h5TlQtF1v110VSTclnnk/s320/compra.03.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3teBIckVaxip_M-5WYwMvNrF32WQZRGv_UWjAnqnLrtJWdYhjohkC8sVnhZbkmexS0dLyUxMj-tuIq3Idds3bv-UL1qewHeSHG20rK5O_OnM2sN2X8-BZGcejt84uWlGrhC4TLGJnzMQ/s1600/compra.04.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;251&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3teBIckVaxip_M-5WYwMvNrF32WQZRGv_UWjAnqnLrtJWdYhjohkC8sVnhZbkmexS0dLyUxMj-tuIq3Idds3bv-UL1qewHeSHG20rK5O_OnM2sN2X8-BZGcejt84uWlGrhC4TLGJnzMQ/s320/compra.04.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
Tras realizar el pago se iniciará la descarga de la actualización. Una vez&amp;nbsp;terminada&amp;nbsp;la descarga nos preguntará que queremos hacer, si instalarla o por ejemplo crear un medio de instalación. En mi caso seleccione está opción, y cree una ISO que yo posteriormente quemé en un DVD y desde el que ahora mismo estoy realizando la instalación de Windows 8 sin problemas. Así que, pese a que estamos comprando una actualización tenemos una ISO que podemos guardar para posteriormente realizar otra instalación.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEha6bM9kXQyVHPn2pLk-DAY1tZUgLo9RRUBviKmmTEnoR2ePHFejnCcBYOnoUKKkLIPMXFfP3SjvoK2L2JAPGbKEYjkYgWVBJXh5tcI90jsY4oJIbzNRHh3WDERw-X_K1yKcNs8VmynHA0/s1600/install.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;250&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEha6bM9kXQyVHPn2pLk-DAY1tZUgLo9RRUBviKmmTEnoR2ePHFejnCcBYOnoUKKkLIPMXFfP3SjvoK2L2JAPGbKEYjkYgWVBJXh5tcI90jsY4oJIbzNRHh3WDERw-X_K1yKcNs8VmynHA0/s320/install.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;b&gt;Notas&lt;/b&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Desde esta página&amp;nbsp;&lt;a href=&quot;https://www.mswos.com/&quot;&gt;https://www.mswos.com/&lt;/a&gt;&amp;nbsp;podemos reiniciar la descarga introduciendo algunos datos como el número de pedido y el apellido y correo electrónico que usamos en la compra.&lt;/li&gt;
&lt;li&gt;La nueva instalación me ha respetado completamente el arranque dual que tenía con Windows 7.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
Happy coding!&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/7060024856615419619/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/10/actualizando-windows-8-pro-desde.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/7060024856615419619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/7060024856615419619'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/10/actualizando-windows-8-pro-desde.html' title='Actualizando a Windows 8 Pro desde Windows 8 Release Preview'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAiqGXgeAP0eHimnDBn2uv2O89od_yxVHZ32pK83stvI-6LEUwQli2uJRQE7FZhtzeHSgq2mh0xC2oef_nmAij01DIK5O9gJnvqRy-O7qkhLcQNkJ1J1SloRbNfdbB0TsW8R7fE1jQzSE/s72-c/upgrade.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-7253086968229518473</id><published>2012-10-24T22:00:00.003+01:00</published><updated>2012-10-24T22:00:56.848+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="general"/><title type='text'>Atajos de teclado en Windows 8</title><content type='html'>A medida que han ido pasando las semanas usando &lt;b&gt;Windows 8&lt;/b&gt; me he ido acostumbrando a usar los&lt;b&gt; atajos de teclado&lt;/b&gt;. Buscando por internet encontré un listado que puede ser útil.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoEj_uoAMPXE1Ie8gVAfVqMdTrOccNOM1vBiJWOd20hyphenhyphen_jiIJerJrbPYZFTSA8XzUmGWvwddfBI7BeVn2Pu7kM8IXgZexqvT1hxmLOckNewyjAtkSEISpPdrMNkXP1LNgU298_r06XusQ/s1600/win8-shortcuts.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoEj_uoAMPXE1Ie8gVAfVqMdTrOccNOM1vBiJWOd20hyphenhyphen_jiIJerJrbPYZFTSA8XzUmGWvwddfBI7BeVn2Pu7kM8IXgZexqvT1hxmLOckNewyjAtkSEISpPdrMNkXP1LNgU298_r06XusQ/s1600/win8-shortcuts.png&quot; height=&quot;262&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Los más que uso son&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;WIN + Q: Para buscar aplicaciones.&lt;/li&gt;
&lt;li&gt;WIN + I: Panel de opciones para luego poder apagar o suspender el equipo.&lt;/li&gt;
&lt;li&gt;WIN + D: Ir al escritorio (esta no es de Windows 8).&lt;/li&gt;
&lt;li&gt;WIN + E: Ir al explorador de Windows (tampoco es exclusiva de Windows 8).&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Os&amp;nbsp;podéis&amp;nbsp;descargar la imagen desde &lt;a href=&quot;https://dl.dropbox.com/u/3157073/win8-shortcuts.png&quot; target=&quot;_blank&quot;&gt;aquí&lt;/a&gt;.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/7253086968229518473/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/10/atajos-de-teclado-en-windows-8.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/7253086968229518473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/7253086968229518473'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/10/atajos-de-teclado-en-windows-8.html' title='Atajos de teclado en Windows 8'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoEj_uoAMPXE1Ie8gVAfVqMdTrOccNOM1vBiJWOd20hyphenhyphen_jiIJerJrbPYZFTSA8XzUmGWvwddfBI7BeVn2Pu7kM8IXgZexqvT1hxmLOckNewyjAtkSEISpPdrMNkXP1LNgU298_r06XusQ/s72-c/win8-shortcuts.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-5298372393568345202</id><published>2012-10-17T20:28:00.002+01:00</published><updated>2012-10-27T13:49:51.119+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="evento"/><title type='text'>Evento. Lanzamiento de Visual Studio 2012</title><content type='html'>Después del éxito del Megathon de Windows 8 organizado por el grupo &lt;a href=&quot;http://www.tenerifedev.com/Inicio/tabid/41/EntryId/31/-Evento-Lanzamiento-de-Visual-Studio-2012-con-TenerifeDev.aspx&quot; target=&quot;_blank&quot;&gt;TenerifeDev&lt;/a&gt; para el &lt;b&gt;próximo 9 de noviembre&lt;/b&gt; hemos preparado unas píldoras de sesiones para enseñaros las múltiples novedades que nos trae la nueva versión del Visual Studio (&lt;b&gt;Visual Studio 2012&lt;/b&gt;). Y digo hemos, porque esta vez me uno al grupo para dar una de las píldoras que se darán.

La idea surge siguiendo la estela del evento que van a celebrar en Madrid la gente de  &lt;a href=&quot;http://madriddotnet.wordpress.com/2012/09/29/lanzamiento-de-visual-studio-2012-con-madriddotnet/&quot;&gt;MadridDotNet&lt;/a&gt;, &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN9ziIaYrOQrb-Sfw1SzmRLBj_aLT1SJQ4V20QMvEnJOc0MhENDg1_6-cvSUVe8XczemeOp_n5dL30sNo8fgYYANcd20dsg34_hFUGNnT8XTrVOgQh6BD0IbajkT9jk2kDZsWNmn00JrY/s1600/logoRegistro.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;45&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN9ziIaYrOQrb-Sfw1SzmRLBj_aLT1SJQ4V20QMvEnJOc0MhENDg1_6-cvSUVe8XczemeOp_n5dL30sNo8fgYYANcd20dsg34_hFUGNnT8XTrVOgQh6BD0IbajkT9jk2kDZsWNmn00JrY/s400/logoRegistro.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Más concretamente daré una charla sobre los nuevos modificadores&amp;nbsp;&lt;b&gt;async&lt;/b&gt; y &lt;b&gt;await&lt;/b&gt; que vienen con el Framework &lt;b&gt;.NET4.5&lt;/b&gt;. Si quieres saber más te recomiendo que asistas al evento, aunque para ir abriendo boca os puedo decir que mediante el uso de async se puede llamar a métodos asíncronos sin definir continuaciones o dividir el código en varios métodos o expresiones lambda de una manera muy simple y quedando un código muy fácil de leer. Después de una pequeña introducción teórica veremos algunos ejemplos de código donde analizaremos como eran las cosas &quot;antes&quot; y como son &quot;ahora&quot; con estos nuevos&amp;nbsp;modificadores.&lt;br /&gt;
&lt;br /&gt;
Para registrarte al evento puedes hacer click en el siguiente &lt;a href=&quot;https://msevents.microsoft.com/CUI/EventDetail.aspx?Culture=es-ES&amp;amp;Eventid=1032533052&quot; target=&quot;_blank&quot;&gt;enlace&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Detalles del evento&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;9 de noviembre&lt;/b&gt;, en las Aulas de la &lt;a href=&quot;http://www.feull.org/&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;Fundación Empresa Universidad de La Laguna&lt;/b&gt;&lt;/a&gt;&amp;nbsp;a la cual hay que agradecer su desinteresada colaboración en este tipo de eventos, &lt;b&gt;de 17.00 a 20.00&lt;/b&gt;. 

Si eres desarrollador o futuro desarrollador, no te puedes perder la siguiente agenda:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://geeks.ms/blogs/adiazmartin/archive/2012/10/17/evento-lanzamiento-de-visual-studio-2012.aspx&quot; target=&quot;_blank&quot;&gt;Novedades de Visual Studio 2012&lt;/a&gt; con Alberto Díaz&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://geeks.ms/blogs/davidjrh/archive/2012/10/21/evento-lanzamiento-de-visual-studio-2012-con-tenerifedev.aspx&quot; target=&quot;_blank&quot;&gt;WebAPI&lt;/a&gt; con David Rodríguez y César Abreu&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://smarrerof.blogspot.com.es/2012/10/evento-lanzamiento-de-visual-studio-2012.html&quot; target=&quot;_blank&quot;&gt;Async/Await&lt;/a&gt; con Sergio Marrero&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://geeks.ms/blogs/adiazmartin/archive/2012/10/17/evento-lanzamiento-de-visual-studio-2012.aspx&quot; target=&quot;_blank&quot;&gt;Windows Phone&lt;/a&gt; con Alberto Díaz&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://geeks.ms/blogs/santypr/archive/2012/10/18/evento-lanzamiento-de-visual-studio-2012-con-tenerifedev.aspx&quot; target=&quot;_blank&quot;&gt;Windows Store&lt;/a&gt; Apps con Santiago Porras&lt;/li&gt;
&lt;/ul&gt;
¡Nos vemos en el evento!&lt;br /&gt;
&lt;br /&gt;
No quiero terminar sin agradecer a&amp;nbsp;&lt;a href=&quot;https://twitter.com/adiazcan&quot; target=&quot;_blank&quot;&gt;Alberto Díaz&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://twitter.com/saintwukong&quot; target=&quot;_blank&quot;&gt;Santiago Porras&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://twitter.com/jose__fortes&quot; target=&quot;_blank&quot;&gt;José Fortes&lt;/a&gt;&amp;nbsp;y&amp;nbsp;&lt;a href=&quot;https://twitter.com/davidjrh&quot; target=&quot;_blank&quot;&gt;David Rodríguez&lt;/a&gt;&amp;nbsp;la oportunidad dar una de las píldoras.</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/5298372393568345202/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/10/evento-lanzamiento-de-visual-studio-2012.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/5298372393568345202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/5298372393568345202'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/10/evento-lanzamiento-de-visual-studio-2012.html' title='Evento. Lanzamiento de Visual Studio 2012'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN9ziIaYrOQrb-Sfw1SzmRLBj_aLT1SJQ4V20QMvEnJOc0MhENDg1_6-cvSUVe8XczemeOp_n5dL30sNo8fgYYANcd20dsg34_hFUGNnT8XTrVOgQh6BD0IbajkT9jk2kDZsWNmn00JrY/s72-c/logoRegistro.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-5221550630549207360</id><published>2012-09-18T14:01:00.000+01:00</published><updated>2012-09-18T14:01:49.453+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="csharp"/><category scheme="http://www.blogger.com/atom/ns#" term="tips"/><title type='text'>Utilizar un número indeterminado de parámetros en C#</title><content type='html'>Tal y como hace el método Format de la clase&amp;nbsp;String hoy he necesitado hacer una función que utilice un número indeterminado, bueno en realidad tres o 4, de parámetros, pero no me apetecía crear 3, 4 o 5 métodos &amp;nbsp;iguales con llamadas de unos a otros. La solución es bien simple y para eso usaremos una característica que nos da C#. Para demostrar su funcionamiento haremos una función que sumará un número indeterminado de número de enteros&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public int Suma(params int[] values)
{
 int suma = 0;
 for (int i = 0; i &amp;lt; values.Length; i++)
  suma += values[i];
 return suma;
}&lt;/pre&gt;
Bastante fácil, ¿verdad?&lt;br /&gt;
&lt;br /&gt;
Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/5221550630549207360/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/09/utilizar-un-numero-indeterminado-de.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/5221550630549207360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/5221550630549207360'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/09/utilizar-un-numero-indeterminado-de.html' title='Utilizar un número indeterminado de parámetros en C#'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-5101060455410544510</id><published>2012-08-30T19:39:00.003+01:00</published><updated>2012-08-30T19:39:35.037+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="test"/><title type='text'>Haciendo test en javascript con jasmine</title><content type='html'>Antes de irme de vacaciones asistí a unas charlas denominadas #jsweek dadas por el grupo &lt;a href=&quot;https://twitter.com/agileCanarias&quot; target=&quot;_blank&quot;&gt;@agileCanarias&lt;/a&gt;. La charlas fueron impartidas por &lt;a href=&quot;https://twitter.com/ydarias&quot; target=&quot;_blank&quot;&gt;@ydarias&lt;/a&gt; y por &lt;a href=&quot;https://twitter.com/axelhzf&quot; target=&quot;_blank&quot;&gt;@axelhzf&lt;/a&gt;, y se tocaron temas tan divertidos como los WTF de javascript, &lt;a href=&quot;http://coffeescript.org/&quot; target=&quot;_blank&quot;&gt;CoffeeScript&lt;/a&gt; y &lt;a href=&quot;http://backbonejs.org/&quot; target=&quot;_blank&quot;&gt;Backbone&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Bien, en la charla de introducción a javascript aprendí a usar &lt;a href=&quot;http://pivotal.github.com/jasmine/&quot; target=&quot;_blank&quot;&gt;jasmine&lt;/a&gt;, que no es otra cosa que un framework para hacer test unitarios en javascript. A medida que&amp;nbsp;escribíamos&amp;nbsp;los test para la &lt;a href=&quot;http://www.solveet.com/exercises/Kata-FizzBuzz/11&quot; target=&quot;_blank&quot;&gt;kata fizzbuzz&lt;/a&gt;&amp;nbsp;me di cuenta que podría aplicar este framework a mi método de comparación de objetos que expliqué en mi anterior post (&lt;a href=&quot;http://smarrerof.blogspot.com.es/2012/08/comparando-objetos-en-javascript.html&quot; target=&quot;_blank&quot;&gt;Comparando objetos en javascript&lt;/a&gt;)&lt;br /&gt;
&lt;br /&gt;
Sin ser un experto, o más bien,&amp;nbsp;considerándome&amp;nbsp;un neófito en esto de los test unitarios, lo primero que debemos hacer es &lt;a href=&quot;https://github.com/pivotal/jasmine/downloads&quot; target=&quot;_blank&quot;&gt;bajarnos&lt;/a&gt; el framework desde su página web. Una vez descargado y descomprimido veremos que tenemos la siguiente estructura&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Un fichero&amp;nbsp;&lt;b&gt;SpecRunner.html&lt;/b&gt; desde donde se ejecutaran los test que definamos.&lt;/li&gt;
&lt;li&gt;Una carpeta lib donde esta el propio framework y donde&amp;nbsp;en principio&amp;nbsp;no tenemos que tocar nada.&lt;/li&gt;
&lt;li&gt;Una carpeta spec donde irán los test que queremos ejecutar.&lt;/li&gt;
&lt;li&gt;Una carpeta src donde irá el código que queremos probrar.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
En mi caso he creado un proyecto llamado HelperJS con un fichero prototypes.js donde está el código descrito en el post anterior y una carpeta test que tiene la estructura anteriormente descrita. Ahora lo que haremos será abrir el fichero SpectRunner.html y añadiremos las referencias a los ficheros de test y ded código que queremos probar.&lt;/div&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;!-- include spec files here... --&amp;gt;
&amp;lt;script type=&quot;text/javascript&quot; src=&quot;spec/prototypesSpec.js&quot;&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;!-- include source files here... --&amp;gt;
&amp;lt;script type=&quot;text/javascript&quot; src=&quot;../prototypes.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;
&lt;div&gt;
Si abrimos la página SpecRunner.html en el navegador obtendremos una página vacia, por lo que lo siguiente será escribir los test en el fichero&amp;nbsp;prototypesSpec.js. Siguiendo un poco la métodología &lt;a href=&quot;http://es.wikipedia.org/wiki/Desarrollo_guiado_por_pruebas&quot; target=&quot;_blank&quot;&gt;TDD&lt;/a&gt; (y repito que soy un novato total en el tema) lo normal es escribir los test de lo más simple a lo más complejo (aunque en mi caso el código ya está escrito).&amp;nbsp;Basándome&amp;nbsp;en esto lo más simple es escribir un test para cuando el segundo objeto es null o undefined. Con esto podemos escribir nuestro primeros test de la siguiente manera&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;describe(&quot;Object.prototype.equals&quot;, function() {
 it(&quot;El objeto a comparar es null&quot;, function() {
  var u1 = {prop1: &quot;1&quot;, prop2: 2};
  var u2 = null;

  expect(u1.equals(u2)).toBe(false);
 });

 it(&quot;El objeto a comparar es undefined&quot;, function() {
  var u1 = {prop1: &quot;1&quot;, prop2: 2};
  var u2 = undefined;

  expect(u1.equals(u2)).toBe(false);
 });
});&lt;/pre&gt;
Como vemos el código es bastante fácil de entender. El método &lt;b&gt;&lt;i&gt;describe&lt;/i&gt;&lt;/b&gt; se usar para definir un grupo de test (u otro grupo) y le pasamos una función donde se definen los test. Para definir un test usamos el método &lt;b&gt;&lt;i&gt;it&lt;/i&gt;&lt;/b&gt;, al que le pasamos una descripción del test y un función donde se ejecuta el test&amp;nbsp;gracias&amp;nbsp;a &lt;b&gt;&lt;i&gt;expect&lt;/i&gt;&lt;/b&gt; donde indicamos lo que&amp;nbsp;queremos&amp;nbsp;probar y el valor que debe tener.&amp;nbsp;Si todo ha ido bien al recargar la página SpecRunner.html debemos obtener algo como esto&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnGRQzIuxIdWuI5Q7gtBG9RqqV0w9E4VdtdUObhyphenhyphen35fbrTAqtyJJ2XpzDgXQbyLcHAk4ZWdVE6Sl5oU2Sqwae0N-8AT7kTQSqAXgWZgMVc4ZrRgTgONcjn0k_7VfkNKQflJAFu_TStmwk/s1600/jasmine01.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;55&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnGRQzIuxIdWuI5Q7gtBG9RqqV0w9E4VdtdUObhyphenhyphen35fbrTAqtyJJ2XpzDgXQbyLcHAk4ZWdVE6Sl5oU2Sqwae0N-8AT7kTQSqAXgWZgMVc4ZrRgTgONcjn0k_7VfkNKQflJAFu_TStmwk/s400/jasmine01.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Con esto claro, ya podemos escribir el resto de test en lo que comprobamos distintas posibilidades que se pueden dar.&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;describe(&quot;Object.prototype.equals&quot;, function() {
 it(&quot;El objeto a comparar es null&quot;, function() {
  var u1 = {prop1: &quot;1&quot;, prop2: 2};
  var u2 = null;

  expect(u1.equals(u2)).toBe(false);
 });

 it(&quot;El objeto a comparar es undefined&quot;, function() {
  var u1 = {prop1: &quot;1&quot;, prop2: 2};
  var u2 = undefined;

  expect(u1.equals(u2)).toBe(false);
 });

 it(&quot;Distinto numero de propiedades&quot;, function() {
  var u1= {prop1 : &quot;value1&quot;, prop2: 2};  
  var u2= {prop1 : &quot;value1&quot;, prop2: 2, prop3: 3};  

  expect(u1.equals(u2)).toBe(false);
 });

 it(&quot;Mismas propiedades pero con distintos valores&quot;, function() {
  var u1= {prop1 : &quot;value1&quot;, prop2: 2};  
  var u2= {prop1 : &quot;value1&quot;, prop2: 3};  

  expect(u1.equals(u2)).toBe(false);
 }); 

 it(&quot;Mismo numero de propiedades pero con nombres distintos&quot;, function() {
  var u1= {prop1 : &quot;value1&quot;, prop2: 2};  
  var u2= {prop1 : &quot;value1&quot;, prop3: 3};  

  expect(u1.equals(u2)).toBe(false);
 }); 
  
 it(&quot;Dos objetos simples iguales&quot;, function() {
  var u1 = {prop1: &quot;1&quot;, prop2: 2};
  var u2 = {prop1: &quot;1&quot;, prop2: 2};

  expect(u1.equals(u2)).toBe(true);
 });

 it(&quot;Dos objetos compuestos distintos&quot;, function() {
  var u1 = {prop1: &quot;1&quot;, prop2: 2, prop3: { prop4: 4}};
  var u2 = {prop1: &quot;1&quot;, prop2: 2, prop3: { prop5: 5}};

  expect(u1.equals(u2)).toBe(false);
 });

 it(&quot;Dos objetos compuestos iguales&quot;, function() {
  var u1 = {prop1: &quot;1&quot;, prop2: 2, prop3: { prop4: 4}};
  var u2 = {prop1: &quot;1&quot;, prop2: 2, prop3: { prop4: 4}};

  expect(u1.equals(u2)).toBe(true);
 });
});&lt;/pre&gt;
Obteniendo la siguiente salida&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzrl3FtpYY2H0Fw6jj7kJ335RaYQrJVJjPiCbibCVZfCBa3HEjbSRjyEoRipEzMpxlmQwLnOXjkW6ihTjccrADcSrToGQp4ncmmsG5zsZm-6JqsY9d4SuYP3WA-kj5Jwk9qg74ws6vzTA/s1600/jasmine02.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;70&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzrl3FtpYY2H0Fw6jj7kJ335RaYQrJVJjPiCbibCVZfCBa3HEjbSRjyEoRipEzMpxlmQwLnOXjkW6ihTjccrADcSrToGQp4ncmmsG5zsZm-6JqsY9d4SuYP3WA-kj5Jwk9qg74ws6vzTA/s400/jasmine02.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Como vemos es bastante fácil escribir test simples para nuestro código javascript. Si estás interesado en probar otros framework de este tipo también está&amp;nbsp;&lt;a href=&quot;http://qunitjs.com/&quot; target=&quot;_blank&quot;&gt;QUnit&lt;/a&gt;&amp;nbsp;que por lo que me han comentado también está bastante bien.&lt;br /&gt;
&lt;br /&gt;
Todo esta código espero subirlo próximamente a GitHub.
&lt;br /&gt;
&lt;br /&gt;
Happy coding!
</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/5101060455410544510/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/08/haciendo-test-en-javascript-con-jasmine.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/5101060455410544510'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/5101060455410544510'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/08/haciendo-test-en-javascript-con-jasmine.html' title='Haciendo test en javascript con jasmine'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnGRQzIuxIdWuI5Q7gtBG9RqqV0w9E4VdtdUObhyphenhyphen35fbrTAqtyJJ2XpzDgXQbyLcHAk4ZWdVE6Sl5oU2Sqwae0N-8AT7kTQSqAXgWZgMVc4ZrRgTgONcjn0k_7VfkNKQflJAFu_TStmwk/s72-c/jasmine01.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-4892439845599640172</id><published>2012-08-10T13:04:00.002+01:00</published><updated>2012-08-10T13:17:24.132+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><title type='text'>Comparando objetos en javascript</title><content type='html'>La verdad es que por muchas horas que invierta en programar en &lt;b&gt;javascript &lt;/b&gt;y en leer esos pequeños detalles que tiene y que pueden volverte loco un par de horas no paro de sorprenderme al ver algunas cosas. La última sin ir más lejos es la siguiente y la mostraré con un simple trozo de código.&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;var u1 = {prop1 : 1, prop2: &quot;value2&quot;};
var u2 = {prop1 : 1, prop2: &quot;value2&quot;};
console.log(u1 == u2); 
console.log(u1 === u2);&lt;/pre&gt;
Simplemente estamos declarando dos objetos y los estamos comparando. Como vemos ambos objetos tienes las mismas propiedades (prop1 y prop2) y los mismos valores en dichas propiedades, prop1 vale 1 y prop2 vale &quot;value2&quot;. Las siguientes lineas muestran por la consola el resultado de comparar ambos objetos. Supongo que la respuesta lógica sería pensar que algunas de las dos comparaciones debería devolver true. ¿Verdad?, pues no, ambas comparaciones devuelve false.
&lt;br /&gt;
&lt;br /&gt;
Si el objeto lo declaramos de otra manera menos que el efecto es el mismo&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;function Foo(p1,p2) {
    this.prop1 = p1;
    this.prop2 = p2;    
}

var u1 = new Foo(1, &quot;value2&quot;);
var u2 = new Foo(1, &quot;value2&quot;);

console.log(u1 == u2);  // false
console.log(u1 === u2); // false&lt;/pre&gt;
Vemos que en ese caso el comportamiento similar así que podemos descartar que este comportamiento sea debido a como hemos declarado nuestros objetos.&lt;br /&gt;
&lt;br /&gt;
Después de pensar un poco en el asunto y necesitando una función que me comparara dos objetos busqué la forma de hacer dicha comparación. Lo primero que determiné es que son para mi dos objetos iguales, y para mi negocio son aquellos objetos cuyas propiedades (solo propiedades y no funciones) sean iguales. O sea que esta comparación sería correcta
&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;function Foo(p1,p2) {
    this.prop1 = p1;
    this.prop2 = p2;
    this.bar = function() {
        // do operation
    }        
}

var u1 = new Foo(1, &quot;value2&quot;);
var u2 = new Foo(1, &quot;value2&quot;);

console.log(u1 == u2);  // false
console.log(u1 === u2); // false&lt;/pre&gt;
Con eso claro lo único que tenemos que hacer es recorrer las propiedades de los objetos implicados e ir comparando valores. Recorrer las propiedades de un objeto es bastante fácil pero puede darnos algún problema si no tenemos algunas cosas en cuenta. En concreto el principal problema es que dependiendo del contexto donde recorramos las propiedades del objeto podemos obtener las propiedades heredadas de dicho objeto, por lo que para evitarlo debemos usar el método hasOwnProperty, que nos asegura que esa propiedad es del objeto en cuestión. En nuestro ejemplo&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;function Foo(p1,p2) {
    this.prop1 = p1;
    this.prop2 = p2;
    this.func1 = function() {
        // do operation
    }        
}

var u1 = new Foo(1, &quot;value2&quot;);
for (var p in u1)
{
  if (u1.hasOwnProperty(p))
    console.log(p);        
}&lt;/pre&gt;
Obtendríamos esta salida&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;prop1
prop2
bar&lt;/pre&gt;
Con esto claro ya podemos intentar hacer nuestro comparador de objetos. La primera versión que se nos viene a la mente es hacer algo así
&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;function equals(p1, p2)
{
    // Comparamos los objetos
}&lt;/pre&gt;
Esta alternativa no es mala, pero pienso que es más elegante extender el tipo object y añadir el método equals, para poder hacer algo así
&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;p1.equals(p2);&lt;/pre&gt;
Esto es bastante fácil en javascript y el esqueleto sería el siguiente&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;Object.prototype.equals = function(x)
{
  // Comparamos los objetos 
}&lt;/pre&gt;
Al principio del método podemos hacer algunas comparaciones básicas como si x no está definido o si los objetos a comparar tienen el mismo número de propiedades. Esta útlima comparación se hace a través del método &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys&quot; target=&quot;_blank&quot;&gt;keys&lt;/a&gt;&amp;nbsp;que desgraciadamente no está disponible en todos los navegadores (se puede consultar su disponibilidad &lt;a href=&quot;http://kangax.github.com/es5-compat-table/&quot; target=&quot;_blank&quot;&gt;aquí&lt;/a&gt;). Con esto, nuestro método ya va tomando cuerpo y sería de la siguiente forma&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;Object.prototype.equals = function(x)
{   
    if (x === null || x === undefined) 
      return false;
            
    if (Object.keys(this).length != Object.keys(x).length)
      return false;
       
    // Comparamos los objetos                             

    return true;                
}&lt;/pre&gt;
Con esto ya lo único que nos queda es recorrer las propiedades del objeto de origen e ir buscando sus homólogas para luego comparar su valor. En estas comparaciones veremos de que tipo es la propiedad, para ver si comparamos directamente sus valores,&amp;nbsp;volvernos&amp;nbsp;a llamar al método equals en caso de ser un objeto o devolvemos false en caso que sea una función. Con esto nuestro método equals quedaría de la siguiente manera&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;Object.prototype.equals = function(x)
{   
    if (x === null || x === undefined) 
        return false;
            
    if (Object.keys(this).length != Object.keys(x).length) return false;
                                   
    for (var p in this)
    {
        // Evitamos navegar por las propiedades &quot;heredadas&quot;
        if (this.hasOwnProperty(p)) {
            // No es una propiedad de x                 
            if (!x.hasOwnProperty(p)) return false;             
            switch(typeof(this[p])) {
                case &#39;function&#39;: 
                    // No admitimos objetos con funciones
                    return false;
                case &#39;object&#39;: 
                    // Comparamos los objetos
                    if (!this[p].equals(x[p]))
                         return false;  
                    break; 
                default:             
                    // Las propiedades tienes valores distintos
                    if (this[p] !== x[p])
                        return false;
                    break;
            }                        
        }
    }

    return true;                
}&lt;/pre&gt;
Para probar este código de manera rudimentaria he hecho este código y lo he lanzado en jsFiddle y los resultado obtenidos son los esperados
&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;var u1= {prop1 : &quot;value1&quot;, prop2: &quot;value2&quot;};
var u2= {prop1 : &quot;value1&quot;, prop2: &quot;value2&quot;};
console.log(&#39;u1 equals u2: &#39; + u1.equals(u2));

var v1= {prop1 : &quot;value1&quot;, prop2: &quot;value2&quot;};
var v2= {prop1 : &quot;value1&quot;, prop2: &quot;value2&quot;, prop3: &quot;value3&quot;};
console.log(&#39;v1 equals v2: &#39; + v1.equals(v2));    

var w1= {prop1 : &quot;value1&quot;, prop2: &quot;value2&quot;};
var w2= {prop1 : &quot;value1&quot;, prop2: &quot;value3&quot;};
console.log(&#39;w1 equals w2: &#39; + w1.equals(w2)); 

var x1= {prop1 : &quot;value1&quot;, prop2: &quot;value2&quot;};
var x2= {prop1 : &quot;value1&quot;, prop3: &quot;value2&quot;};
console.log(&#39;x1 equals x2: &#39; + x1.equals(x2));

var y1= {prop1 : &quot;value1&quot;, prop2: { prop3: &quot;value3&quot;}};
var y2= {prop1 : &quot;value1&quot;, prop2: { prop4: &quot;value4&quot;}};
console.log(&#39;y1 equals y2: &#39; + y1.equals(y2));

var z1= {prop1 : &quot;value1&quot;, prop2: { prop3: &quot;value3&quot;}};
var z2= {prop1 : &quot;value1&quot;, prop2: { prop3: &quot;value3&quot;}};
console.log(&#39;z1 equals z2: &#39; + z1.equals(z2));&lt;/pre&gt;
Puedes probar este código desde &lt;a href=&quot;http://kcy.me/acwb&quot; target=&quot;_blank&quot;&gt;aquí&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Se que esta no es la manera más óptima de probar el código y para esto existen framework de javascript como &lt;a href=&quot;http://pivotal.github.com/jasmine/&quot; target=&quot;_blank&quot;&gt;Jasmine&lt;/a&gt; o &lt;a href=&quot;http://qunitjs.com/&quot; target=&quot;_blank&quot;&gt;QUnit&lt;/a&gt; pero esta parte la dejaré para otro post.&lt;br /&gt;
&lt;br /&gt;
En definitiva hemos visto que hay que estar atentos a muchos comportamientos que tiene javascript ya que algo tan simple como una comparación de objetos puede ser una vez más una tarea complicada.&lt;br /&gt;
&lt;br /&gt;
Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/4892439845599640172/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/08/comparando-objetos-en-javascript.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/4892439845599640172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/4892439845599640172'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/08/comparando-objetos-en-javascript.html' title='Comparando objetos en javascript'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-9029966726942386883</id><published>2012-08-07T13:51:00.002+01:00</published><updated>2012-08-07T13:51:34.407+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><title type='text'>Los operadores de comparación en javascript</title><content type='html'>Desde hace algún tiempo cada vez invierto más horas de mi jornada laboral en programar en javascript. A medida que vas programando en este lenguaje te vas dando cuenta de las muchas peculiaridades que tiene, y que te puede arruinar una jornada laboral.&lt;br /&gt;
&lt;br /&gt;
Para los que vienen de programar en lenguajes como C# este tipo de sentencias son de lo más normales&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;if (a == b) { 
  // a y b son iguales
}&lt;/pre&gt;
El problema está en que javascript las cosas no son como nosotros estamos acostumbrados que sean y este comparador nos pueden dar algún que otro quebradero de cabeza y más teniendo en cuenta que&amp;nbsp;también&amp;nbsp;tenemos un triple comparador, si como lo oyes, tenemos un triple comparador que se escribe &lt;b&gt;===&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Entonces, ¿cuál es la diferencia entre == y ===? Pues bien, el doble comparador por decirlo de una manera hace una comparación por valor y en caso que los tipos no sean igual javascript hace una coerción de tipos. El triple comparador, al contrario que el doble comparador, por decirlo de alguna manera fuerza la igualdad de tipos y del valor que estamos comparando.&lt;br /&gt;
&lt;br /&gt;
Sabiendo esto, tenemos que estar atento a la hora de comparar variables porque javascript puede resolver la&amp;nbsp;comparación&amp;nbsp;de la manera que nosotros no esperamos.&lt;br /&gt;
&lt;br /&gt;
Algunos ejemplos para que todo quede más claro&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;1 == 1            // true como era de esperar
1 == &quot;1&quot;          // true, se convierte la cadena de texto a numero
null == undefined // true
1 == true         // true
&quot;&quot; == false       // true
&#39;\n&#39; == false     // true, el &#39;\n&#39; se interpreta como la cadena vacía
&quot;&quot; == 0           // true
&#39;\n&#39; == 0         // true&lt;/pre&gt;
Como vemos en todas las comparaciones (salvo la primera) esperaríamos que javascript nos devolviera false, sin embargo nos devuelve true. Para salvar esto deberíamos usar el triple comparador.&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;1 === 1            // sigue siendo true
1 === &quot;1&quot;          // false
null === undefined // false
1 === true         // false
&quot;&quot; === false       // false
&#39;\n&#39; === false     // false
&quot;&quot; === 0           // false
&#39;\n&#39; === 0         // false&lt;/pre&gt;
De igual forma que tenemos == y ===, también tenemos &lt;b&gt;!=&lt;/b&gt; y &lt;b&gt;!==&lt;/b&gt; cuyo comportamiento es análogo.&lt;br /&gt;
&lt;br /&gt;
Otras comparaciones curiosas pero menos comunes son&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;NaN == NaN  // false, NaN es Not a Number y no se puede comparar
NaN === NaN // false
1.0 == 1    // true
1.0 === 1   // true, para javascript ambos son de tipo numeric
&lt;/pre&gt;
La coerción de tipos puede ser algo realmente frustrante y que nos puede volver locos un par horas, pero que nos puede venir bastante bien en algunas situaciones por lo que lo mejor es estar seguro de lo que estamos haciendo en cada momento.&lt;br /&gt;
&lt;br /&gt;
Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/9029966726942386883/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/08/los-operadores-de-comparacion-en.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/9029966726942386883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/9029966726942386883'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/08/los-operadores-de-comparacion-en.html' title='Los operadores de comparación en javascript'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-2384775174697993845</id><published>2012-08-06T11:20:00.001+01:00</published><updated>2012-08-06T11:20:50.869+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="knockout"/><title type='text'>Introducción a Knockout (VIII) - obsersable computed y binding event</title><content type='html'>Con los &lt;b&gt;binding&lt;/b&gt; que trae &lt;b&gt;knockout&lt;/b&gt; de fábrica debería ser más que suficiente para la mayoría de los proyectos en los que usemos knockout. Pese a ésto knockout nos brinda la forma de poder extender estos comportamientos predefinidos para poder tener un control total sobre nuestra vista y así no tener prácticamente ninguna limitación.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Computed Observables&lt;/b&gt;&lt;br /&gt;
Dentro de los observables que nos da knockout tenemos los &lt;i&gt;computed observables&lt;/i&gt; (prefiero no traducirlo).&amp;nbsp;Son funciones, que depende de uno o más &lt;i&gt;observables&lt;/i&gt; y que se actualizan automáticamente cuando una de sus&amp;nbsp;dependencias&amp;nbsp;cambia. Típicamente se usan para información que se muestra en solo lectura aunque como veremos más adelante también los &lt;i&gt;computed observables&lt;/i&gt; pueden ser de escritura y ellos a su vez puede actualizar valores.&lt;br /&gt;
&lt;br /&gt;
Supongamos esta &lt;b&gt;vista&lt;/b&gt;&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;p&amp;gt;Nombre: &amp;lt;input type=&quot;text&quot; data-bind=&quot;value: firstname&quot; /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Apellidos: &amp;lt;input type=&quot;text&quot; data-bind=&quot;value: lastname&quot; /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Nombre completo: &amp;lt;label data-bind=&quot;text: name&quot;&amp;gt;&amp;lt;/p&amp;gt;&lt;/pre&gt;
Y este &lt;b&gt;modelo&lt;/b&gt;&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;function ViewModel(model) {  
    var self = this;  
  
    self.firstname = ko.observable(&#39;&#39;);  
    self.lastname = ko.observable(&#39;&#39;);  
    self.name = ko.computed(function() {
        if (self.firstname() == &#39;&#39; || self.lastname() == &#39;&#39;) return &#39;&#39;;
         return self.lastname() + &#39;, &#39; + self.firstname();
    });
}  

var viewModel = new ViewModel();  
ko.applyBindings(viewModel);​&lt;/pre&gt;
Como vemos establecemos dos observables sobre &lt;i&gt;firstname&lt;/i&gt; y &lt;i&gt;lastname&lt;/i&gt;. También definimos &lt;i&gt;observable computed&lt;/i&gt; que actualiza la propiedad &lt;i&gt;name&lt;/i&gt;. Esta función se lanzará cada vez que la propiedades &lt;i&gt;lastname&lt;/i&gt; y &lt;i&gt;firstname&lt;/i&gt; cambien. Lo realmente maravilloso es que la función detecta a que propiedades debe detectar los cambios sin que nosotros debamos hacer nada más que usarlas en el cuerpo de la función.&lt;br /&gt;
&lt;br /&gt;
Podemos probar este ejemplo en el siguiente &lt;a href=&quot;http://jsfiddle.net/SgkbD/1/&quot; target=&quot;_blank&quot;&gt;enlace&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Como comentamos antes, los &lt;i&gt;computed observables&lt;/i&gt; también pueden ser de escritura y ellos actualizar determinados valores. He de reconocer que esto no suele ser muy común pero puede que en algún momento nos sea útil. Para hacer un &lt;i&gt;computed observables&lt;/i&gt; de lectura y escritura en el ejemplo anterior cambiaremos la vista&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;p&amp;gt;Nombre: &amp;lt;input type=&quot;text&quot; data-bind=&quot;value: firstname&quot; /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Apellidos: &amp;lt;input type=&quot;text&quot; data-bind=&quot;value: lastname&quot; /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Nombre completo: &amp;lt;input type=&quot;text&quot; data-bind=&quot;value: name&quot;&amp;gt;&amp;lt;/p&amp;gt;&lt;/pre&gt;
y el modelo de la siguiente manera&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;function ViewModel(model) {  
    var self = this;  
  
    self.firstname = ko.observable(&#39;&#39;);  
    self.lastname = ko.observable(&#39;&#39;);  
    self.name = ko.computed({
        read: function() {
            if (self.firstname() == &#39;&#39; || self.lastname() == &#39;&#39;) return &#39;&#39;;
                return self.lastname() + &#39;, &#39; + self.firstname();
        },
        write: function(value) {
            var index = value.lastIndexOf(&quot;, &quot;);
            if (index &amp;gt; 0) 
            { 
                self.firstname(value.substring(index + 2));
                self.lastname(value.substring(0, index));
            }
        }
    });
}  

var viewModel = new ViewModel();  
ko.applyBindings(viewModel);​&lt;/pre&gt;
Tal y como hicimos antes, si actualizamos el nombre y los apellidos automáticamente se actualizará el campo del nombre del completo. La salvedad en este caso, es que si actualizamos el nombre completo nosotros con el formato apellidos, nombre, se actualizarán los campos nombre y apellidos.&lt;br /&gt;
&lt;br /&gt;
Podemos probar este ejemplo en el siguiente&amp;nbsp;&lt;a href=&quot;http://jsfiddle.net/XeQYL/&quot; target=&quot;_blank&quot;&gt;enlace&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Binding Event&lt;/b&gt;&lt;br /&gt;
Otra de las posibilidades que nos da knockout es trabajar directamente con los eventos que tienes javascript, pese a que ya tenemos algunos bindings que trabajan con ellos como puede ser el binding click.&lt;br /&gt;
Por ejemplo, si definimos la siguiente vista&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;div&amp;gt;
    &amp;lt;input type=&quot;text&quot; data-bind=&quot;value: message, event: { keyup: onkeyup }&quot; /&amp;gt;
    &amp;lt;label data-bind=&quot;text: status&quot; &amp;gt;&amp;lt;/label&amp;gt;
&amp;lt;/div&amp;gt;​&lt;/pre&gt;
y el siguiente modelo&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;function ViewModel(model) {  
    var self = this; 

    self.message = ko.observable(&#39;&#39;);
    self.status = ko.observable(&#39;Has escrito 0 caracteres...&#39;);
  
    self.onkeyup = function(data, event) {
        self.status(&#39;Has escrito &#39; + event.target.value.length + &#39; caracteres...&#39;);           
        return true;
    }
}  
ko.applyBindings(new ViewModel());&lt;/pre&gt;
En este ejemplo estamos enganchándonos al evento keyup de un textbox y actualizamos un label con la información del número de caracteres que hemos introducido en el textbox.&lt;br /&gt;
&lt;br /&gt;
Podemos probar este ejemplo en el siguiente&amp;nbsp;&lt;a href=&quot;http://jsfiddle.net/ZpFJB/&quot; target=&quot;_blank&quot;&gt;enlace&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
Como vemos, knoutout es bastante&amp;nbsp;versátil&amp;nbsp;y prácticamente podemos hacer lo que queramos. En el próximo artículo veremos como hacer nuestros propios bindings que también nos pueden ser útiles en algunos contextos.&lt;br /&gt;
&lt;br /&gt;
Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/2384775174697993845/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/08/introduccion-knockout-viii-computed.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/2384775174697993845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/2384775174697993845'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/08/introduccion-knockout-viii-computed.html' title='Introducción a Knockout (VIII) - obsersable computed y binding event'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-7915015741664686711</id><published>2012-07-31T06:50:00.000+01:00</published><updated>2012-07-31T06:50:05.180+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="metro"/><category scheme="http://www.blogger.com/atom/ns#" term="windows 8"/><title type='text'>GridView, mostrando datos en tiempo de diseño</title><content type='html'>Algo que puede resulta molesto a la hora de trabajar con el &lt;b&gt;GridView&lt;/b&gt; es que no vemos el aspecto que éste tendrá hasta que no ejecutamos la aplicación. Esto puede suponer una gran perdida de tiempo si estamos en una fase en la que estamos &quot;depurando&quot; nuestra UI.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Para mostrar datos en el diseñador&lt;/b&gt; debemos declararlos en el &lt;b&gt;XAML&lt;/b&gt; en vez a través de la propiedad DataContext. Esto es así porque el diseñador parsea el XAML pero no ejecuta el code-behind.&amp;nbsp;Existen varias alternativas para conseguir esto, así que vamos a ver una de ellas. Lo primero que&amp;nbsp;haremos será definir nuestro origen de datos&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public class MenuModel
{
    public int IdMenu { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

public class MenuModelList : List&amp;lt;MenuModel&amp;gt;
{
    public MenuModelList()
    {
        this.Add(new MenuModel() { IdMenu = 1, Name = &quot;Name 1&quot;, Description = &quot;Description 1&quot; });
        this.Add(new MenuModel() { IdMenu = 2, Name = &quot;Name 2&quot;, Description = &quot;Description 2&quot; });
    }
}&lt;/pre&gt;
Después declararemos este objeto como un recurso para que pueda referenciado por otros elementos de la siguiente manera&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;Page.Resources&amp;gt;
    &amp;lt;local:MenuModelList x:Key=&quot;MenuListData&quot;/&amp;gt;
    &amp;lt;CollectionViewSource x:Name=&quot;MenuListResource&quot;
        Source=&quot;{StaticResource MenuListData}&quot;/&amp;gt;        
&amp;lt;/Page.Resources&amp;gt;&lt;/pre&gt;
Y lo referenciaremos desde nuestro GridView de la siguiente forma&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;GridView x:Name=&quot;GridViewMenu&quot;
            HorizontalAlignment=&quot;Left&quot; 
            Margin=&quot;19,70,0,0&quot; 
            Grid.Row=&quot;1&quot; 
            VerticalAlignment=&quot;Top&quot; 
            SelectionMode=&quot;None&quot;
            IsItemClickEnabled=&quot;True&quot;                                                       
            ItemsSource=&quot;{Binding Source={StaticResource MenuListResource}}&quot;&amp;gt;

    &amp;lt;!-- Resto de información del GridView --&amp;gt;
&amp;lt;/GridView&amp;gt;&lt;/pre&gt;
De esta manera veremos nuestro GridView en tiempo de diseño de la siguiente manera&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioDKCh3BRXuuAXXlM2zJZSiWAZ1oNWT7ZUu0GrCcXIovmc0LqitFvIP6Z2-seXXZ-5bfP_OBM96cxMZbd7_dkl_VFLMpUZOAjzOS9_Qy5DXvGN9E1-yTYb5kkRHBeABt2UQ7J4c-vh0Og/s1600/GridViewDesignMode.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;270&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioDKCh3BRXuuAXXlM2zJZSiWAZ1oNWT7ZUu0GrCcXIovmc0LqitFvIP6Z2-seXXZ-5bfP_OBM96cxMZbd7_dkl_VFLMpUZOAjzOS9_Qy5DXvGN9E1-yTYb5kkRHBeABt2UQ7J4c-vh0Og/s400/GridViewDesignMode.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;GridView en tiempo de diseño&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
El único&amp;nbsp;inconveniente&amp;nbsp;del modelo planteado anteriormente es que esos datos serán los mismos que se usarán cuando nuestra aplicación esté en ejecución. Si queremos usar otros datos en ejecución podemos optar por cambiar el origen de datos en el constructor de&amp;nbsp;nuestro&amp;nbsp;modelo en base a si estamos en tiempo de diseño o en tiempo de ejecución. Para conseguir esto podemos hacer los siguiente&lt;br /&gt;&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public class MenuModelList : List&amp;lt;MenuModel&amp;gt; {
    public MenuModelList()
    {
        if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
            GetSampleData();
        else
            GetRealData();
    }

    private void GetSampleData()
    {
        this.Add(new MenuModel() { IdMenu = 1, Name = &quot;Name 1&quot;, Description = &quot;Description 1&quot; });
        this.Add(new MenuModel() { IdMenu = 2, Name = &quot;Name 2&quot;, Description = &quot;Description 2&quot; });
    }

    private void GetRealData()
    {
        this.Add(new MenuModel() { IdMenu = 1, Name = &quot;Elemento 1&quot;, Description = &quot;Descripción del elemento 1&quot; });
        this.Add(new MenuModel() { IdMenu = 2, Name = &quot;Elemento 2&quot;, Description = &quot;Descripción del elemento 2&quot; });
    }
}&lt;/pre&gt;
Si ejecutamos ahora nuestra aplicaciones veremos que obtenemos otros datos distintos a los que obteníamos en tiempo de diseño.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_Irdwv4agZRbFiL1qbdLpnI0oU3WgGuN5I6N_MRSw0F8B5EKykMA9ewhIAmE8Wio4oTqcWZux9m-Yq-RCpgdBS8TtRaP9hbeWH2mvGoEzg6LYLi_NRfhZgOj7TwFu2nmLEyOd210z1aA/s1600/GridViewRuntime.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;250&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_Irdwv4agZRbFiL1qbdLpnI0oU3WgGuN5I6N_MRSw0F8B5EKykMA9ewhIAmE8Wio4oTqcWZux9m-Yq-RCpgdBS8TtRaP9hbeWH2mvGoEzg6LYLi_NRfhZgOj7TwFu2nmLEyOd210z1aA/s400/GridViewRuntime.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;GridView en tiempo de ejecución&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Como vemos es relativamente fácil mostrar información en nuestros GridView en tiempo de ejecución lo cual hace que el diseño de nuestra aplicación sea más fácil de llevar a cabo porque evitaremos infinidad de ejecuciones innecesarias.&lt;br /&gt;
&lt;br /&gt;
Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/7915015741664686711/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/07/gridview-mostrando-datos-en-tiempo-de.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/7915015741664686711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/7915015741664686711'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/07/gridview-mostrando-datos-en-tiempo-de.html' title='GridView, mostrando datos en tiempo de diseño'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioDKCh3BRXuuAXXlM2zJZSiWAZ1oNWT7ZUu0GrCcXIovmc0LqitFvIP6Z2-seXXZ-5bfP_OBM96cxMZbd7_dkl_VFLMpUZOAjzOS9_Qy5DXvGN9E1-yTYb5kkRHBeABt2UQ7J4c-vh0Og/s72-c/GridViewDesignMode.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-6949742116878818034</id><published>2012-07-27T18:12:00.000+01:00</published><updated>2012-07-27T18:12:14.211+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="metro"/><category scheme="http://www.blogger.com/atom/ns#" term="windows 8"/><title type='text'>Diferencias entre DataContext y ItemsSource en Metro</title><content type='html'>Para aquellos que no tengamos demasiada experiencia en WPF o Silverlight el bindeo de datos puede ser un poco confuso teniendo en cuenta que parece que se puede hacer de dos maneras distintas, tanto a&amp;nbsp;través&amp;nbsp;de la propiedad &lt;b&gt;DataContext &lt;/b&gt;como de la propiedad &lt;b&gt;ItemsSource&lt;/b&gt;. Pese a que puedan parecer propiedades idénticas nada más lejos de la realidad ya que ambas propiedades tienen un propósito bien distinto.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;DataContext &lt;/b&gt;es una propiedad general de todos los descendientes de &lt;b&gt;FrameworkElement&lt;/b&gt;. Es heredada a de padres a hijos y puede ser usada como origen de datos para el &lt;b&gt;DataBinding&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;ItemsSource &lt;/b&gt;es una propiedad que identifica la generación de elementos de los controles que derivan de &lt;b&gt;ItemsControl&lt;/b&gt;. Cuando establecemos esta propiedad a través de DataBinding o&amp;nbsp;vía&amp;nbsp;código el control generará los elementos internamente. Estableciendo la propiedad DataContext en un ItemsControls no provocaremos el mismo efecto.&lt;br /&gt;
&lt;br /&gt;
Bien, pero como no sólo de teoría vive el desarrollador vamos a ver esto en un ejemplo. Imaginemos que tenemos esta clase&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public class MenuModel
{
    public int IdMenu { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}&lt;/pre&gt;
Y que inicializamos una lista de elementos de la siguiente manera&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;List&amp;lt;MenuModel&amp;gt; items = new List&amp;lt;MenuModel&amp;gt;();
items.Add(new MenuModel() { IdMenu = 1, Name = &quot;Elemento 1&quot;, Description = &quot;Descripción del elemento 1&quot; });
items.Add(new MenuModel() { IdMenu = 2, Name = &quot;Elemento 2&quot;, Description = &quot;Descripción del elemento 2&quot; });
&lt;/pre&gt;
Bien con esto podremos hacer lo siguiente sobre un GridView&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;GridViewMenu.ItemsSource = items;&lt;/pre&gt;
O sea, aplicaremos como origen de datos la colección de elementos única y exclusivamente al GridView. El resultado será este&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZtUZkQaU9h0LEjAUvBxMYfflTcVxMvgWw48mWxy1bFKiyjfuLcPTtpmLId8l1uv2STuHujJMwmfFSRQo_JtBpRAG3YFXkzfvhuSI7WZjstkGzUy4mOzCk3e8WV3fmEXebR7C28KoeGts/s1600/GridViewItemsSource.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;255&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZtUZkQaU9h0LEjAUvBxMYfflTcVxMvgWw48mWxy1bFKiyjfuLcPTtpmLId8l1uv2STuHujJMwmfFSRQo_JtBpRAG3YFXkzfvhuSI7WZjstkGzUy4mOzCk3e8WV3fmEXebR7C28KoeGts/s400/GridViewItemsSource.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;GridView&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Bien, ahora cambiaremos la llamada a ItemsSource por DataContext y veremos que ocurre. Correcto, lo que ocurre es que no se ha generado el GridView y eso porque el ItemsSource si lanza la generación del control pero el DataContext no. Para que se genere el control debemos modificar el DataBind del GridView &amp;nbsp;de la siguiente manera&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;GridView x:Name=&quot;GridViewMenu&quot;
            HorizontalAlignment=&quot;Left&quot;
            Margin=&quot;19,70,0,0&quot;
            Grid.Row=&quot;1&quot;
            VerticalAlignment=&quot;Top&quot;
            SelectionMode=&quot;None&quot;
            IsItemClickEnabled=&quot;True&quot;
            ItemTemplate=&quot;{StaticResource itemTemplate}&quot;
            ItemsSource=&quot;{Binding}&quot;&amp;gt;&lt;/pre&gt;
&lt;br /&gt;
Bien, pero con DataContext podemos hacer algunas cosas más como hemos comentado antes. Vamos a crear un modelo que tenga nuestra lista de elemento y un texto y vamos a ver como podemos hacer el bindeo de datos de una manera muy simple.
&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public class MainPageModel
{
    public string Titulo { get; set; }
    public List&amp;lt;MenuModel&amp;gt; Items { get; set; }

    public MainPageModel()
    {
        this.Titulo = &quot;Mi título&quot;;

        Items = new List&amp;lt;MenuModel&amp;gt;();
        Items.Add(new MenuModel() { IdMenu = 1, Name = &quot;Elemento 1&quot;, Description = &quot;Descripción del elemento 1&quot; });
        Items.Add(new MenuModel() { IdMenu = 2, Name = &quot;Elemento 2&quot;, Description = &quot;Descripción del elemento 2&quot; });
    }
}&lt;/pre&gt;
Como hemos dicho antes DataContext es una propiedad que se programa por toda la jerarquía de hijos, así que la asignaremos al DataContext de la página&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;this.DataContext = model;&lt;/pre&gt;
Y en el diseñador pondremos también un TextBox de la siguiente manera
&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;TextBlock HorizontalAlignment=&quot;Left&quot; Height=&quot;24&quot; Margin=&quot;18,16,0,0&quot; Grid.Row=&quot;1&quot; TextWrapping=&quot;Wrap&quot; Text=&quot;{Binding Titulo}&quot; FontSize=&quot;24&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;339&quot;/&amp;gt;
&amp;lt;GridView x:Name=&quot;GridViewMenu&quot;
            HorizontalAlignment=&quot;Left&quot;
            Margin=&quot;19,70,0,0&quot;
            Grid.Row=&quot;1&quot;
            VerticalAlignment=&quot;Top&quot;
            SelectionMode=&quot;None&quot;
            IsItemClickEnabled=&quot;True&quot;
            ItemTemplate=&quot;{StaticResource itemTemplate}&quot;
            ItemsSource=&quot;{Binding Items}&quot;&amp;gt;
    &amp;lt;GridView.ItemsPanel&amp;gt;
        &amp;lt;ItemsPanelTemplate&amp;gt;
            &amp;lt;StackPanel Orientation=&quot;Horizontal&quot;/&amp;gt;
        &amp;lt;/ItemsPanelTemplate&amp;gt;
    &amp;lt;/GridView.ItemsPanel&amp;gt;&lt;/pre&gt;
El resultado de esto es el siguiente&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqEoq7tC1ELLEV5gdwZAC5ct9VxEwBXzSad7DnN6NwpOTVF4JcPVdPS7QiwH9TV_Y1bjLeATQWG7xkdgBe9zuoLxwnjFAjOBpmyfnotNbkr7GHC8y-IDy6ZUQNGWRRqRBr9rjrhS7bpF4/s1600/GridViewDataContext.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;255&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqEoq7tC1ELLEV5gdwZAC5ct9VxEwBXzSad7DnN6NwpOTVF4JcPVdPS7QiwH9TV_Y1bjLeATQWG7xkdgBe9zuoLxwnjFAjOBpmyfnotNbkr7GHC8y-IDy6ZUQNGWRRqRBr9rjrhS7bpF4/s400/GridViewDataContext.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;GridView
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
En lineas generales podemos decir que usaremos ItemsSource si solo vamos a enlazar un ItemsControl con un único origen de datos y si tenemos varios elementos que van consumir nuestro&amp;nbsp;origen&amp;nbsp;de datos usaremos DataContext.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Nota&lt;/b&gt;: En el fichero StandardStyles.xaml tengo definida la siguiente Template para definir es aspecto del GridView&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;!-- DataTemplates --&amp;gt;
&amp;lt;DataTemplate x:Key=&quot;itemTemplate&quot;&amp;gt;
    &amp;lt;Grid Background=&quot;DarkGray&quot; Width=&quot;250&quot; Height=&quot;250&quot;&amp;gt;
        &amp;lt;StackPanel Orientation=&quot;Vertical&quot; VerticalAlignment=&quot;Bottom&quot; Margin=&quot;0,0,0,10&quot;&amp;gt;
            &amp;lt;TextBlock Text=&quot;{Binding Name}&quot; 
                    FontSize=&quot;24&quot;  Margin=&quot;10,0,0,0&quot; 
                    TextTrimming=&quot;WordEllipsis&quot; TextWrapping=&quot;Wrap&quot; 
                    HorizontalAlignment=&quot;Left&quot;/&amp;gt;
            &amp;lt;TextBlock Text=&quot;{Binding Description}&quot; 
                    FontSize=&quot;12&quot; Margin=&quot;10,0,0,0&quot; 
                    TextTrimming=&quot;WordEllipsis&quot; TextWrapping=&quot;Wrap&quot; 
                    HorizontalAlignment=&quot;Left&quot;/&amp;gt;
        &amp;lt;/StackPanel&amp;gt;
    &amp;lt;/Grid&amp;gt;
&amp;lt;/DataTemplate&amp;gt;&lt;/pre&gt;
&lt;br /&gt;
Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/6949742116878818034/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/07/diferencias-entre-datacontext-y.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/6949742116878818034'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/6949742116878818034'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/07/diferencias-entre-datacontext-y.html' title='Diferencias entre DataContext y ItemsSource en Metro'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZtUZkQaU9h0LEjAUvBxMYfflTcVxMvgWw48mWxy1bFKiyjfuLcPTtpmLId8l1uv2STuHujJMwmfFSRQo_JtBpRAG3YFXkzfvhuSI7WZjstkGzUy4mOzCk3e8WV3fmEXebR7C28KoeGts/s72-c/GridViewItemsSource.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-6787825331242553664</id><published>2012-07-26T10:21:00.001+01:00</published><updated>2012-07-26T10:31:32.521+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="knockout"/><title type='text'>Introducción a Knockout (VII) - La propiedad $index</title><content type='html'>El otro día estaba revisando la documentación de &lt;b&gt;&lt;a href=&quot;http://knockoutjs.com/documentation/foreach-binding.html&quot; target=&quot;_blank&quot;&gt;binding foreach&lt;/a&gt;&lt;/b&gt; de &lt;b&gt;&lt;a href=&quot;http://knockoutjs.com/&quot; target=&quot;_blank&quot;&gt;knockout&lt;/a&gt;&lt;/b&gt; cuando recordé que una de las novedades que había traído la versión 2.1.0 era la inclusión de la propiedad &lt;b&gt;$index&lt;/b&gt; dentro del contexto &lt;b&gt;foreach&lt;/b&gt;. Pensando que utilidad podría tener dentro de una aplicación real y que no fuera la de simplemente mostrar un índice ya que eso lo podemos tener usando &lt;a href=&quot;http://www.w3schools.com/tags/tag_ol.asp&quot; target=&quot;_blank&quot;&gt;&amp;lt;ol&amp;gt;&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Pensando un poco se me ocurrió un ejemplo donde nos podría ser útil esta nueva propiedad, así que s&lt;span style=&quot;background-color: white;&quot;&gt;upongamos que tenemos una &lt;/span&gt;&lt;b style=&quot;background-color: white;&quot;&gt;colección de elementos&lt;/b&gt;&lt;span style=&quot;background-color: white;&quot;&gt; de este tipo&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public class Item
{
 public int IdItem { get; set; }
 public string Description { get; set; }
 public int Quantity { get; set; }
}&lt;/pre&gt;
Esta colección de elementos se la tenemos que presentar al usuario y este debe escribir las cantidades que quiere para cada Item, y enviarla de nuevo al servidor. Se podría ver como un versión muy reducida de un carrito de la compra, donde tenemos los elementos que queremos comprar y podemos modificar la cantidad de elementos. Bien, para mostrar esta información y para simplificar el ejemplo he creado la&amp;nbsp;siguiente&amp;nbsp;modelo y acciones&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Modelo&lt;/b&gt;&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public class Model
{
 public List&amp;lt;Item&amp;gt; Items { get; set; }
}&lt;/pre&gt;
&lt;b&gt;Acciones&lt;/b&gt;&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public ActionResult Index()
{
 Model model = new Model();
 FillModel(model);

 return View(model);
}

[HttpPost()]
public ActionResult Index(Model model)
{
 return RedirectToAction(&quot;Index&quot;);
}

private void FillModel(Model model)
{
 model.Items = new List&amp;lt;Item&amp;gt;();
 for (int i = 1; i &amp;lt;= 10; i++)
  model.Items.Add(new Item() { IdItem = i, Description = string.Format(&quot;Item{0}&quot;, i), Quantity = 0 });
}&lt;/pre&gt;
&lt;b&gt;Vista&lt;/b&gt;&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;h2&amp;gt;Items&amp;lt;/h2&amp;gt;
@using (Html.BeginForm())
{ 
 for(int i = 0; i &amp;lt; Model.Items.Count; i++)
 {
  &amp;lt;div&amp;gt;
   @Html.HiddenFor(m =&amp;gt; Model.Items[i].IdItem)
   @Html.HiddenFor(m =&amp;gt; Model.Items[i].Description)
   @Model.Items[i].Description
   @Html.TextBoxFor(m =&amp;gt; Model.Items[i].Quantity)
  &amp;lt;/div&amp;gt;
 }
 &amp;lt;input type=&quot;submit&quot; value=&quot;Enviar&quot; /&amp;gt;
}&lt;/pre&gt;
El aspecto de este formulario sería el siguiente&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyQFDWQBsisNw0IpLWVprhdZZ0-r1Yxofo1VJeG7I1UGZ_SML3PjrbRtl_4Kkx7iFIBoxVSJw7w1bz9XNuL9n4aTQ-HAWyNADxl-euCekMXbsYNzZ7uWZ6oWwJ9eNijRnpR-pdqX8r4bQ/s1600/view.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyQFDWQBsisNw0IpLWVprhdZZ0-r1Yxofo1VJeG7I1UGZ_SML3PjrbRtl_4Kkx7iFIBoxVSJw7w1bz9XNuL9n4aTQ-HAWyNADxl-euCekMXbsYNzZ7uWZ6oWwJ9eNijRnpR-pdqX8r4bQ/s320/view.jpg&quot; width=&quot;272&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Vista&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Bien, si modificamos alguna de las cantidades y le damos a enviar, obtendremos esto en la controladora&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzjLyn0bw3Isdo0C-zcIlEJvbbiThp4AQif22etpZrH5J8NsnSv9b-FSswgoAZTrGMFWdAPlwCWUwzPsTArtavQa1U64x4LnGjtgW5Lp3ouNgkLvy3uqUKimuLR6eamI_-_anterjuOmY/s1600/viewpost.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;112&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzjLyn0bw3Isdo0C-zcIlEJvbbiThp4AQif22etpZrH5J8NsnSv9b-FSswgoAZTrGMFWdAPlwCWUwzPsTArtavQa1U64x4LnGjtgW5Lp3ouNgkLvy3uqUKimuLR6eamI_-_anterjuOmY/s320/viewpost.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Post&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Como vemos el valor introducido por el usuario&amp;nbsp;&lt;span style=&quot;background-color: white;&quot;&gt;(10)&lt;/span&gt;&lt;span style=&quot;background-color: white;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white;&quot;&gt;ha sido &quot;bindeado&quot; en nuestro modelo sin problemas. Bien, ahora supongamos que queremos hacer lo mismo pero usando &lt;/span&gt;&lt;b style=&quot;background-color: white;&quot;&gt;knockout&lt;/b&gt;&lt;span style=&quot;background-color: white;&quot;&gt;. Para eso, debemos modificar ligeramente la vista de la siguiente manera.&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;@using (Html.BeginForm())
{ 
 &amp;lt;!-- ko foreach: items --&amp;gt;
 &amp;lt;div&amp;gt;
  &amp;lt;input type=&quot;hidden&quot; data-bind=&quot;value: IdItem&quot;  /&amp;gt;
  &amp;lt;input type=&quot;hidden&quot; data-bind=&quot;value: Description&quot;  /&amp;gt;
  &amp;lt;span data-bind=&quot;text: Description&quot;&amp;gt;&amp;lt;/span&amp;gt;
  &amp;lt;input type=&quot;text&quot; data-bind=&quot;value: Quantity&quot;  /&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;!-- /ko --&amp;gt;
 &amp;lt;input type=&quot;submit&quot; value=&quot;Enviar&quot; /&amp;gt;
}

&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
 $(document).ready(function () {
  function ViewModel(model) {
   var self = this;

   self.items = ko.observableArray(model.Items);
  }
  var viewModel = new ViewModel(@Html.Raw(Json.Encode(Model)));
  ko.applyBindings(viewModel);
 });
&amp;lt;/script&amp;gt;&lt;/pre&gt;
Con esto veremos que nuestra vista es igual a la obtenida anteriormente, pero al enviar el form nos daremos cuenta que nuestro modelo no se &quot;bindea&quot; correctamente.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmpJ-dt5EmOsMcumnI3RrtapUhCw3fTX2KA3oglP6rQPBX1VbKyRdeLfxlJ1vfnuo9siPPsuWvyyPv65LsWqu1SdXGdLWtOh1cLnfC21we5_JGSlkdpeaHnde3uvgyw6J07gLbJcGdysc/s1600/viewposterror.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;87&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmpJ-dt5EmOsMcumnI3RrtapUhCw3fTX2KA3oglP6rQPBX1VbKyRdeLfxlJ1vfnuo9siPPsuWvyyPv65LsWqu1SdXGdLWtOh1cLnfC21we5_JGSlkdpeaHnde3uvgyw6J07gLbJcGdysc/s320/viewposterror.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Si sabemos como funciona el bind de ASP.NET MVC veremos que este error es lógico ya que los elementos que estamos poniendo en nuestra vista no tienen el atributo name definido, pero además hay que tener en cuenta que estamos intentando &quot;bindear&quot; una colección por lo que tendremos que especificar el índice que ocupa el elemento en la colección. Para esto es para lo que viene de maravilla el uso de la propiedad &lt;b&gt;$index&lt;/b&gt; dentro del contexto foreach (no es que antes no se pudiera hacer, sino que era más complicado). Con esto la vista quedaría de la siguiente manera&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;!-- ko foreach: items --&amp;gt;
&amp;lt;div&amp;gt;
 &amp;lt;input type=&quot;hidden&quot; data-bind=&quot;value: IdItem, attr: {name: &#39;Items[&#39;+$index()+&#39;].IdItem&#39;}&quot;  /&amp;gt;
 &amp;lt;input type=&quot;hidden&quot; data-bind=&quot;value: Description, attr: {name: &#39;Items[&#39;+$index()+&#39;].Description&#39;}&quot;  /&amp;gt;
 &amp;lt;span data-bind=&quot;text: Description&quot;&amp;gt;&amp;lt;/span&amp;gt;
 &amp;lt;input type=&quot;text&quot; data-bind=&quot;value: Quantity, attr: {name: &#39;Items[&#39;+$index()+&#39;].Quantity&#39;}&quot;  /&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;!-- /ko --&amp;gt;&lt;/pre&gt;
Esto generaría el siguiente código html que vemos que cumple con lo dicho anteriormente&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZbIAVN-L7mlNvUGpr1T3DRXngwgauP30zfS3e_8dzQN1T6jq9PQcVLuFM6aoan5NoWqhmey2s1zxmaVLcXg9YhSMWj3WoMmaA2lJjVszByX0uhA299Ep0W5FgJUGh4D9GrJzTSIii4nM/s1600/htmlview.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;147&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZbIAVN-L7mlNvUGpr1T3DRXngwgauP30zfS3e_8dzQN1T6jq9PQcVLuFM6aoan5NoWqhmey2s1zxmaVLcXg9YhSMWj3WoMmaA2lJjVszByX0uhA299Ep0W5FgJUGh4D9GrJzTSIii4nM/s400/htmlview.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Vista HTML&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Y si hacemos el post veremos que el modelo se ha &quot;bindeado&quot; de nuevo correctamente&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzjLyn0bw3Isdo0C-zcIlEJvbbiThp4AQif22etpZrH5J8NsnSv9b-FSswgoAZTrGMFWdAPlwCWUwzPsTArtavQa1U64x4LnGjtgW5Lp3ouNgkLvy3uqUKimuLR6eamI_-_anterjuOmY/s1600/viewpost.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;112&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzjLyn0bw3Isdo0C-zcIlEJvbbiThp4AQif22etpZrH5J8NsnSv9b-FSswgoAZTrGMFWdAPlwCWUwzPsTArtavQa1U64x4LnGjtgW5Lp3ouNgkLvy3uqUKimuLR6eamI_-_anterjuOmY/s320/viewpost.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;NOTA&lt;/b&gt;&lt;br /&gt;
Hay otra forma de generar la vista de una manera más &quot;elegante&quot; y evitando así tener que usar un bucle y teniendo a nuestra alcance el Intellisense es la siguiente. Creamos una página parcial (Partial Page) llamada Item.cshtml &amp;nbsp;(mismo nombre que la clase que contiene la colección) en el directorio View/Home/RenderPartials o Shared/RenderPartials y en ella pondremos lo siguiente&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;@model test.web.mvc.cs.Models.Item

&amp;lt;div&amp;gt;
 @Html.HiddenFor(m =&amp;gt; m.IdItem)
 @Html.HiddenFor(m =&amp;gt; m.Description)
 @Model.Description
 @Html.TextBoxFor(m =&amp;gt; m.Quantity)
&amp;lt;/div&amp;gt;&lt;/pre&gt;
Luego en la vista tan solo deberemos poner lo siguiente&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;@using (Html.BeginForm())
{ 
 @Html.EditorFor(x =&amp;gt; x.Items)
 &amp;lt;input type=&quot;submit&quot; value=&quot;Enviar&quot; /&amp;gt;
}&lt;/pre&gt;
&lt;br /&gt;
Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/6787825331242553664/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/07/introduccion-knockout-vii-la-propiedad.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/6787825331242553664'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/6787825331242553664'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/07/introduccion-knockout-vii-la-propiedad.html' title='Introducción a Knockout (VII) - La propiedad $index'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyQFDWQBsisNw0IpLWVprhdZZ0-r1Yxofo1VJeG7I1UGZ_SML3PjrbRtl_4Kkx7iFIBoxVSJw7w1bz9XNuL9n4aTQ-HAWyNADxl-euCekMXbsYNzZ7uWZ6oWwJ9eNijRnpR-pdqX8r4bQ/s72-c/view.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-6030394537250579158</id><published>2012-07-24T10:38:00.001+01:00</published><updated>2012-07-24T10:38:43.327+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="metro"/><category scheme="http://www.blogger.com/atom/ns#" term="windows 8"/><title type='text'>Controles comunes en aplicaciones Metro</title><content type='html'>Desde hace un par de días estoy iniciándome en el desarrollo de aplicaciones &lt;b&gt;Metro&lt;/b&gt; para &lt;b&gt;Windows 8&lt;/b&gt;. Una vez instalado &lt;a href=&quot;http://windows.microsoft.com/es-XL/windows-8/download/&quot; target=&quot;_blank&quot;&gt;Windows 8 Release Preview&lt;/a&gt; y el &lt;a href=&quot;http://www.microsoft.com/visualstudio/11/en-us/downloads&quot; target=&quot;_blank&quot;&gt;Visual Studio 2012 RC&lt;/a&gt; tenemos todo lo necesario para comenzar con el desarrollo de este tipo de aplicaciones.&lt;br /&gt;
&lt;br /&gt;
Una vez arrancado el Visual Studio seleccionaremos la plantilla &lt;b&gt;Windows Metro Style&lt;/b&gt; en el lenguaje que más nos guste tal y como se muestra en la imagen&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeLtqDJgBIFTjdXFWEGH14CriEH-2rm23GiQYUz5qMhpyVi_hNq_LNbKu_Tkgzaekd7oTrJif-tXQQARqzpBwDb88Bi-xOy7XM-azO56odlr6Gp33baGwi_m2eWIYWWlmTr5oEIRVxvdE/s1600/WindowsMetroStyle.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;220&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeLtqDJgBIFTjdXFWEGH14CriEH-2rm23GiQYUz5qMhpyVi_hNq_LNbKu_Tkgzaekd7oTrJif-tXQQARqzpBwDb88Bi-xOy7XM-azO56odlr6Gp33baGwi_m2eWIYWWlmTr5oEIRVxvdE/s320/WindowsMetroStyle.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Tras esto se nos creará un proyecto de éste tipo con el siguiente aspecto&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqYcGPjrvZ2zvATd37fVxp9uPK7aNS9MtkV25stWlbLxRVMBTj4ZiN-JcexUg120FxHXgUEpMVBBa-Ke2lr0DE-JkM0N9ifyWrWhqWdC-eYzE2o6Q1s-jtfoW1Rrk_8INPzO23CTNc9tA/s1600/MetroProject.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqYcGPjrvZ2zvATd37fVxp9uPK7aNS9MtkV25stWlbLxRVMBTj4ZiN-JcexUg120FxHXgUEpMVBBa-Ke2lr0DE-JkM0N9ifyWrWhqWdC-eYzE2o6Q1s-jtfoW1Rrk_8INPzO23CTNc9tA/s1600/MetroProject.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
En este primer artículo voy a hablar un poco de los controles que tenemos a nuestra disposición para desarrollar para Metro ya que la lista puede agobiar un poco al principio, o al menos esa fue mi primera impresión ya que siempre he trabajado para aplicaciones web o como mucho alguna aplicación de&amp;nbsp;escritorio&amp;nbsp;de tipo WinForms y nunca he hecho nada serio para &lt;b&gt;WPF&lt;/b&gt; o &lt;b&gt;Silverlight&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;u&gt;Controles más comunes&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Border&lt;/b&gt;: Dibuja un borde, un fondo o ambos alrededor de un objeto.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;Border BorderBrush=&quot;Black&quot; BorderThickness=&quot;1&quot; 
        Height=&quot;120&quot; Width=&quot;60&quot;&amp;gt;
    &amp;lt;StackPanel&amp;gt;
        &amp;lt;Rectangle Fill=&quot;Red&quot;/&amp;gt;
        &amp;lt;Rectangle Fill=&quot;Green&quot;/&amp;gt;
    &amp;lt;/StackPanel&amp;gt;
&amp;lt;/Border&amp;gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Button&lt;/b&gt;: Representa un control de tipo botón que interpreta un click del usuario.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;Button .../&amp;gt;
-or-
&amp;lt;Button&amp;gt;
    singleObject
&amp;lt;/Button&amp;gt;
-or-
&amp;lt;Button ...&amp;gt;stringContent&amp;lt;/Button&amp;gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;CheckBox&lt;/b&gt;: Representa un control que el usuario puede marcar (check) o desmarcar (uncheck). Este control también puede tener un valor indeterminado.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;CheckBox .../&amp;gt;
-or-
&amp;lt;CheckBox&amp;gt;
  singleObject
&amp;lt;/CheckBox&amp;gt;
-or-
&amp;lt;CheckBox&amp;gt;stringContent&amp;lt;/CheckBox&amp;gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;ComboBox&lt;/b&gt;: Control de selección que combina un textbox no editable y un drop-down list que permite al usuario seleccionar un elemento de una lista.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;ComboBox x:Name=&quot;ComboColores&quot; Height=&quot;20&quot; Width=&quot;150&quot; ItemsSource=&quot;{Binding}&quot; /&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;ObservableCollection&amp;lt;string&amp;gt; colores = new ObservableCollection&amp;lt;string&amp;gt;();
colores.Add(&quot;Rojo&quot;);
colores.Add(&quot;Verde&quot;);
colores.Add(&quot;Azul&quot;);
     
ComboColores.DataContext = colores;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;FlipView&lt;/b&gt;: Representa un control para mostrar elementos, pero que muestra un elemento cada vez, y tiene un comportamiento de &quot;flip&quot; cuando se pasa de uno a otro.&lt;/li&gt;
&lt;/ul&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXPhAWA80rE9ZaaX9rfIrAr1DZSXiI3HhM-PrPvTFt6OZE4570ghgGq1JhqiE5nKcTonDPfdKt_em5IGyneWPie3ncZeIvVQ8m30zt4lIvcGZmiEfWp3wEPobprS4audjgWjAeqMTwxzY/s1600/flip.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;233&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXPhAWA80rE9ZaaX9rfIrAr1DZSXiI3HhM-PrPvTFt6OZE4570ghgGq1JhqiE5nKcTonDPfdKt_em5IGyneWPie3ncZeIvVQ8m30zt4lIvcGZmiEfWp3wEPobprS4audjgWjAeqMTwxzY/s400/flip.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Control FlipView usado para mostrar una galería de imágenes&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Grid&lt;/b&gt;: Define un área flexible organizada en filas y columnas. Los elementos hijos son organizados en base a la cantidad de filas y columnas definidas.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GridView&lt;/b&gt;: Muestra un Grid horizontal de elementos de datos.&lt;/li&gt;
&lt;/ul&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-87ws0Ahv0uiXU1GqlcHfTd5IGOiqsVQpCHpMdL_roKU2xZbCeP4endoeuZFmY7uJY6DDImrtd3RVE1-V98BCZnyZLzJcCQRaD4uhXscXKi-krY2wi7YZXkebDNZBXAd514rltQ1B3I4/s1600/GridView.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;180&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-87ws0Ahv0uiXU1GqlcHfTd5IGOiqsVQpCHpMdL_roKU2xZbCeP4endoeuZFmY7uJY6DDImrtd3RVE1-V98BCZnyZLzJcCQRaD4uhXscXKi-krY2wi7YZXkebDNZBXAd514rltQ1B3I4/s320/GridView.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Metro GridView&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Image&lt;/b&gt;: Control que muestra una imagen. La imagen puede estar en varios formatos (Joint Photographic Experts Group [JPEG], Portable Network Graphics [PNG],
Bitmap [BMP], Graphics Interchange Format [GIF], Tagged Image File Format [TIFF], JPEG XR, icons [ICO]).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ListView&lt;/b&gt;: Muestra una lista de elementos de manera vertical.&lt;/li&gt;
&lt;/ul&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjF7HgTCsFEJD07tpVYYGwUTzhnY4vPdaLOG_JurXcha2NFbMBH6u7DEagFOKSm_T9xJyfBqyuje6FE0OZ_jq1Sr3Pld0B93yAveCvxQrn4YOroRjCTstKH0ZOru7qJCX87nxTTWfnji5A/s1600/ListView.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;231&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjF7HgTCsFEJD07tpVYYGwUTzhnY4vPdaLOG_JurXcha2NFbMBH6u7DEagFOKSm_T9xJyfBqyuje6FE0OZ_jq1Sr3Pld0B93yAveCvxQrn4YOroRjCTstKH0ZOru7qJCX87nxTTWfnji5A/s320/ListView.png&quot; width=&quot;96&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Metro ListView&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;RadioButton&lt;/b&gt;: Le permite al&amp;nbsp;usuario&amp;nbsp;seleccionar una opción de un grupo de opciones.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;StackPanel&lt;/b&gt;: Organiza una lista de elementos hijo en una única fila que puede ser orientada de manera vertical u horizontal.&lt;/li&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;StackPanel x:Name=&quot;MyStackPanel&quot;&amp;gt;
  &amp;lt;TextBlock x:Name=&quot;TextFirstName&quot; Text=&quot;Nombre&quot; Width=&quot;75&quot; HorizontalAlignment=&quot;Left&quot;/&amp;gt;
  &amp;lt;TextBlock x:Name=&quot;TextLastName&quot; Text=&quot;Apellidos&quot; Width=&quot;75&quot; HorizontalAlignment=&quot;Left&quot;/&amp;gt;
  &amp;lt;TextBlock x:Name=&quot;TextAddress&quot; Text=&quot;Dirección&quot; Width=&quot;150&quot; HorizontalAlignment=&quot;Left&quot;/&amp;gt;
&amp;lt;/StackPanel&amp;gt;&lt;/pre&gt;
&lt;li&gt;&lt;b&gt;TextBlock&lt;/b&gt;: Control que nos ayuda a mostrar una pequeña&amp;nbsp;cantidad&amp;nbsp;de texto.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;TextBlock ...&amp;gt;text&amp;lt;/TextBlock&amp;gt;
-or-
&amp;lt;TextBlock&amp;gt;
  oneOrMoreInlineElements
&amp;lt;/TextBlock&amp;gt;
-or-
&amp;lt;TextBlock .../&amp;gt;&lt;/pre&gt;
&lt;div&gt;
&lt;b&gt;&lt;u&gt;Otros controles que nos pueden ser útiles&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;AppBar&lt;/b&gt;:&amp;nbsp;Representa un control contenedor que contiene los componentes de interfaz de usuario para ejecutar acciones.&lt;/li&gt;
&lt;/ul&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7rcucH_Lu8iHTzZ9FIjI2_xKSbQVDM38Q7l1-tETQxK8CD3HioxbeOeC-rOJJw_8LfI1laePVRd5j1J8qHhrkoBNEhHJd2xC8VmsM1GEsmiq_BxDum0z0MUr79rLQE5ucXLC8H_a52dc/s1600/AppBar.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;66&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7rcucH_Lu8iHTzZ9FIjI2_xKSbQVDM38Q7l1-tETQxK8CD3HioxbeOeC-rOJJw_8LfI1laePVRd5j1J8qHhrkoBNEhHJd2xC8VmsM1GEsmiq_BxDum0z0MUr79rLQE5ucXLC8H_a52dc/s400/AppBar.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Metro AppBar&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Canvas&lt;/b&gt;: Define un área en la que pueden colocarse explícitamente objetos, usando coordenadas que son relativas al &quot;Canvas&quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;Canvas Width=&quot;640&quot; Height=&quot;480&quot; &amp;gt;
    &amp;lt;Rectangle Canvas.Left=&quot;30&quot; Canvas.Top=&quot;30&quot; 
       Fill=&quot;Red&quot; Width=&quot;200&quot; Height=&quot;200&quot; /&amp;gt;
&amp;lt;/Canvas&amp;gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;background-color: white;&quot;&gt;&lt;b&gt;Frame&lt;/b&gt;: Representa un control de contenido que soporta la navegación.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MediaElement&lt;/b&gt;: Representa un objeto que contiene audio,&amp;nbsp;vídeo&amp;nbsp;o ambos.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;MediaElement Source=&quot;Media/video1.mp4&quot; AutoPlay=&quot;True&quot; /&amp;gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;SemanticZoom: Representa un control con scroll que contiene dos vistas que tienen una relación semántica.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;&amp;lt;SemanticZoom ...&amp;gt;
  &amp;lt;SemanticZoom.ZoomedOutView&amp;gt;
    zoomedOutViewContent
  &amp;lt;/SemanticZoom.ZoomedOutView&amp;gt;
  &amp;lt;SemanticZoom.ZoomedInView&amp;gt;
    zoomedInViewContent
  &amp;lt;/SemanticZoom.ZoomedInView&amp;gt;
&amp;lt;/SemanticZoom&amp;gt;&lt;/pre&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQLtyqT0s3Uvh0eecZXQZB-EsxKGGcmBus7RDFbSBpAUUna7pdFrGIjvr_r9YrCir2CoroN9gCyp1193hm_lQdPwm0-gzKFi8NhPwSrYN1NSkgyQL41DIreOMAgdU0QobU13_wztAYHsA/s1600/SemanticZoom1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;180&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQLtyqT0s3Uvh0eecZXQZB-EsxKGGcmBus7RDFbSBpAUUna7pdFrGIjvr_r9YrCir2CoroN9gCyp1193hm_lQdPwm0-gzKFi8NhPwSrYN1NSkgyQL41DIreOMAgdU0QobU13_wztAYHsA/s320/SemanticZoom1.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Metro SemanticZoom&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8QDbonoKC5_-laoHi7Emf9aU8beGjaUjzBYf3MCrQzMvVt4gogC-nX_ZJ6LEddq8Fd4U1Wl9V4US2l0j_CUg0ggcGeK4JGCrWEqlYEvX7TyULFe0kI5_J_WV8t23548vYdFqTJrrgxeQ/s1600/SemanticZoom2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;180&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8QDbonoKC5_-laoHi7Emf9aU8beGjaUjzBYf3MCrQzMvVt4gogC-nX_ZJ6LEddq8Fd4U1Wl9V4US2l0j_CUg0ggcGeK4JGCrWEqlYEvX7TyULFe0kI5_J_WV8t23548vYdFqTJrrgxeQ/s320/SemanticZoom2.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Metro SemanticZoom
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;Slider: Representa un control que permite al usuario seleccionar un valor dentro de un rango.&lt;/li&gt;
&lt;/ul&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3njyhSRi6hfUN6RWogbe6Ny0SfLEjYVYRXNC3wACaeV1W3himpLR4rroOP6OPwGvWW6k6puqtX6pQP-U3_NwWKDG-1H7Ql8XwcZBal1QxjwAi32hAUGavDgWAr3pPYDu8rpZYJSFYjDs/s1600/Slider.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;97&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3njyhSRi6hfUN6RWogbe6Ny0SfLEjYVYRXNC3wACaeV1W3himpLR4rroOP6OPwGvWW6k6puqtX6pQP-U3_NwWKDG-1H7Ql8XwcZBal1QxjwAi32hAUGavDgWAr3pPYDu8rpZYJSFYjDs/s320/Slider.png&quot; width=&quot;144&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Metro Slider&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;Con esto acabamos la introducción a los controles que tenemos a nuestra disposición en la aplicaciones Metro. En los próximos artículos iremos viendo como utilizarlos dentro de nuestras aplicaciones.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/6030394537250579158/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/07/controles-comunes-en-aplicaciones-metro.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/6030394537250579158'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/6030394537250579158'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/07/controles-comunes-en-aplicaciones-metro.html' title='Controles comunes en aplicaciones Metro'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeLtqDJgBIFTjdXFWEGH14CriEH-2rm23GiQYUz5qMhpyVi_hNq_LNbKu_Tkgzaekd7oTrJif-tXQQARqzpBwDb88Bi-xOy7XM-azO56odlr6Gp33baGwi_m2eWIYWWlmTr5oEIRVxvdE/s72-c/WindowsMetroStyle.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-3355942112878674973</id><published>2012-07-04T12:40:00.000+01:00</published><updated>2012-07-04T12:40:32.449+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="csharp"/><category scheme="http://www.blogger.com/atom/ns#" term="entity framework"/><title type='text'>Entity Framework y el borrado de entidades (II) - usando lambda y árboles de expresión</title><content type='html'>Como ya explique en el artículo anterior la forma más natural de borrar un registro es a través de su clave primaria, aunque eso no siempre tiene porque ser así. Un par de ejemplos sobre esto puede ser&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Borrar aquellos registros que tengan más de un año de&amp;nbsp;antigüedad. Práctico en tablas de logs.&lt;/li&gt;
&lt;li&gt;Borrar aquellos registros que tengan un estado determinado.&lt;/li&gt;
&lt;li&gt;O simplemente querer borrar registros en base a una clave ajena, como por ejemplo, borrar todas los lineas de una factura.&lt;/li&gt;
&lt;/ul&gt;
En todos estos casos la solución planteada en el artículo anterior no nos valdría ya que asumimos que tan sólo vamos a borrar un registro.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Borrado de varias entidades
&lt;/b&gt;&lt;br /&gt;
Basándonos en este ejemplo&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public class Bar
{
  public int IdBar { get; set; }
  public string Description { get; set; }
  public int IdState { get; set; }
}&lt;/pre&gt;
y queriendo borrar aquellos registros que estén en el estado 1 podríamos hacer lo 
siguiente&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;using (DataContext context = new DataContext())
{
  var list = context.Bar.Where(m =&amp;gt; m.IdState == 1);
  foreach (Bar bar in list)
    context.Bar.Remove(bar);
  context.SaveChanges();
}&lt;/pre&gt;
Si analizamos el código anterior veremos que para borrar n elementos, debemos hacer n + 1 accesos a la base de datos. Lanzaremos n consultas de borrado, y necesitaremos una más para recuperar los elementos a borrar.
&lt;br /&gt;
&lt;br /&gt;
Como últimamente me he vuelto un&amp;nbsp;inconformista&amp;nbsp;esta solución no me gusta porque para borrar 1000 elementos necesito hacer 1001 acceso a base de datos y eso me parece demasiada carga para un servidor, que en mi caso, ya anda demasiado justo de recursos.&lt;br /&gt;
&lt;br /&gt;
La primera solución que se me ocurrió fue usar un método de este estilo&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;using (DataContext context = new DataContext())
{
  context.Database.ExecuteSqlCommand(&quot;DELETE FROM Bar WHERE IdState = @IdState&quot;, new 
object[] { new System.Data.SqlClient.SqlParameter(&quot;IdState&quot;, 1) });
}&lt;/pre&gt;
Esta solución es bastante buena aunque me deja atado a una tabla y a un filtro en concreto, lo cual me obliga a estar estableciendo métodos por cada tabla donde desee borrar un conjunto de datos y si uso varios filtros a estar usando parámetros opcionales (que suelen afear el código bastante).&lt;br /&gt;
&lt;br /&gt;
Para mi lo ideal sería en un sólo método poder resolver esta situación, y tras investigar un poco se puede hacer con algo de código extra. Dado que estoy usando Code First he creado un método Delete en el contexto con el siguiente aspecto&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public void Delete&amp;lt;T&amp;gt;(Expression&amp;lt;Func&amp;lt;T, bool&amp;gt;&amp;gt; condition)
{
  string where = generateWhere(condition.Body);
  string query = String.Format(&quot;DELETE FROM {0} WHERE {1}&quot;, typeof(T).Name, where);
  ((IObjectContextAdapter)this).ObjectContext.ExecuteStoreCommand(query);
}&lt;/pre&gt;
De esta manera puedo pasar que entidad estoy intentado borrar y los filtros que voy a usar en el borrado. Antes de continuar me gustaría aclarar que transformar un &lt;a href=&quot;http://msdn.microsoft.com/es-es/library/bb397951.aspx&quot; target=&quot;_blank&quot;&gt;árbol de expresion&lt;/a&gt; a una condición SQL no es una tarea fácil y esta llena de pequeño matices que puede que hagan que no sea rentable realizar el esfuerzo. En mi caso las condiciones de borrado son muy simples y la mejora de rendimiento (que veremos al final) justificaban el pequeño esfuerzo que ha llevado el desarrollo de este método. Pero ojo, hacer un &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/bb546158.aspx&quot; target=&quot;_blank&quot;&gt;LINQ Provider&lt;/a&gt; no es una tarea que se pueda considerar trivial.
&lt;br /&gt;
&lt;br /&gt;
Bien, con esto podríamos llamar a nuestro método de borrado de la siguiente manera&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;using (DataContext context = new DataContext())
{
  context.Delete&amp;lt;Bar&amp;gt;(m =&amp;gt; m.IdState == 1);
}&lt;/pre&gt;
Si analizamos nuestra &lt;b&gt;Expression&lt;/b&gt; de entrada vemos como tiene una propiedad &lt;b&gt;Body&lt;/b&gt; donde está la/s condiciones que hemos pasado y que tenemos que transformar a una condición Where de SQL. En esta propiedad tenemos tanto la parte izquierda como la parte derecha de la condición, así como el operador que se está usando. En el método generateWhere analizaremos todas estas partes para devolver un Where válido.&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;private string generateWhere(dynamic operation)
{
  string left = generateToken(ExpressionTypeEnum.Left, operation.Left);
  string right = generateToken(ExpressionTypeEnum.Right, operation.Right);

  // TODO: Completar operaciones (por ahora con estas es suficiente)
  var ops = new Dictionary&lt;expressiontype, string=&quot;&quot;&gt;();
  ops.Add(ExpressionType.Equal, &quot;=&quot;);
  ops.Add(ExpressionType.GreaterThan, &quot;&amp;gt;&quot;);
  ops.Add(ExpressionType.GreaterThanOrEqual, &quot;&amp;gt;=&quot;);
  ops.Add(ExpressionType.LessThan, &quot;&amp;lt;&quot;);
  ops.Add(ExpressionType.LessThanOrEqual, &quot;&amp;lt;=&quot;);

  ops.Add(ExpressionType.And, &quot;AND&quot;);
  ops.Add(ExpressionType.AndAlso, &quot;AND&quot;);
  ops.Add(ExpressionType.Or, &quot;OR&quot;);
  ops.Add(ExpressionType.OrElse, &quot;OR&quot;);

  return string.Format(&quot;{0} {1} {2}&quot;, left, ops[operation.NodeType], right);
}&lt;/expressiontype,&gt;&lt;/pre&gt;
En mi caso estoy tomando como base que la &lt;b&gt;Expression&lt;/b&gt; es de tipo &lt;b&gt;BinaryExpression&lt;/b&gt; aunque más exactamente es de tipo &lt;b&gt;LogicalBinaryExpression&lt;/b&gt; (esto lo podemos comprobar en tiempo de ejecución). En otras expresiones este análisis de la&amp;nbsp;expresión&amp;nbsp;fallaría por no tener alomejor una propiedad Right.&lt;br /&gt;
&lt;br /&gt;
Vemos que tanto para la parte izquierda como para la parte derecha llamamos al método generateToken que se encarga de generarnos una cadena con el valor contenido en esa parte, e incluso, de llamar recursivamente al método generateWhere en caso que estemos combinado filtros de esta manera&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;using (DataContext context = new DataContext())
{
  context.Delete&amp;lt;Bar&amp;gt;(m =&amp;gt; m.IdState == 1 || m.IdState == 2);
}&lt;/pre&gt;
El método generateToken tendría el siguiente aspecto&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;private string generateToken(ExpressionTypeEnum type, dynamic operation)
{
  string token = string.Empty;
  if (operation is BinaryExpression)
    token = generateWhere(operation);
  else
    token = (type == ExpressionTypeEnum.Left ? operation.Member.Name : operation.Value.ToString());
   
  return token;
}&lt;/pre&gt;
Como único detalle hay que tener en cuenta que dependiendo de que parte de la expresión estemos analizando extraeremos el token de una u otra propiedad.
&lt;br /&gt;
&lt;br /&gt;
Con esto ya tenemos nuestro pequeño &quot;parser&quot; listo para ser usado en un entorno controlado y con condiciones simples. He detectados otras expresiones que poco a poco iré añadiendo. Estas expresiones son&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.linq.expressions.unaryexpression.aspx&quot; target=&quot;_blank&quot;&gt;UnaryExpression&lt;/a&gt;. Para filtros de tipo m =&amp;gt; !m.IsActive. Donde IsActive es de tipo boolean.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://msdn.microsoft.com/es-es/library/system.web.ui.webcontrols.expressions.propertyexpression.aspx&quot; target=&quot;_blank&quot;&gt;PropertyExpression&lt;/a&gt;: Para filtros de tipo m=&amp;gt; m.IsActive.
Donde IsActive es de tipo boolean.&lt;/li&gt;
&lt;li&gt;MethodBinaryExpression: Para filtros de tipo m=&amp;gt;m.Date &amp;lt; DateTime.Now. Donde como es lógico Date es de tipo DateTime.&lt;/li&gt;
&lt;/ul&gt;
Para ver la mejora de rendimiento he realizado un borrado iterativo y un borrado con esté método usando el siguiente código&lt;br /&gt;
&lt;b&gt;Iterativo&lt;/b&gt;&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;using (DataContext context = new DataContext())
{
  var list = context.Bar.Where(m =&amp;gt; m.IdState == 1);
  foreach (Bar bar in list)
    context.Bar.Remove(bar);
  context.SaveChanges(); 
}&lt;/pre&gt;
&lt;b&gt;Directo&lt;/b&gt;&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;using (DataContext context = new DataContext())
{
  context.Delete&amp;lt;Bar&amp;gt;(m =&amp;gt; m.IdState == 1);
}&lt;/pre&gt;
&lt;br /&gt;
He lanzado estos métodos borrado 10, 100, 1000 y 10000 elementos. Cada bloque lo he lanzado tres veces y he calculado la media para dar la duración de la duración. Con estas condiciones estos son los datos que he obtenido&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTcFRlSqAd5z09IhWBdJ5h-Velmf7_T9-2JW2R3o039ETCaNQb7DBFlx0td-ImxVvvoivYWPLypbdKmLlqicDnXiydSy07SDBruNoGoGK7MH2nL6adLAITDfgLBWrT1jC2CzS4DO_gzVE/s1600/estadisticas.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;60&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTcFRlSqAd5z09IhWBdJ5h-Velmf7_T9-2JW2R3o039ETCaNQb7DBFlx0td-ImxVvvoivYWPLypbdKmLlqicDnXiydSy07SDBruNoGoGK7MH2nL6adLAITDfgLBWrT1jC2CzS4DO_gzVE/s400/estadisticas.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Registros a borrar - Tiempo de ejecución en ms&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;b&gt;Conclusiones&lt;/b&gt;&lt;br /&gt;
Como vemos en la tabla para borrados de más de 1000 registros el borrado iterativo se puede vuelve un poco pesado, ya que nos lleva casi 4 segundos ejecutarlo (producto de tener que lanzar 1001 consultas a la base de datos), mientra que nuestro borrado directo no llega a los 12 ms. En condiciones más extremas (10.000 registros) el borrado iterativo llega a casi 2 minutos de ejecución mientras que el directo no nos pasa de un cuarto de segundo. Interesante, ¿verdad?&lt;br /&gt;
&lt;br /&gt;
En la mayoría de los escenarios no merece la pena complicarnos la vida tanto ya que tan solo borraremos un par de registros y podemos optar por el método iterativo, ya que como vemos entre ambos métodos para 10 registros casi no tenemos diferencias de tiempos. Para borrados de más registros siempre podemos optar procedimientos almacenados o lanzar directamente nosotros la consultas desde nuestro programa, pero si queremos tener a nuestra disposición mucho filtros para borrar está opción nos puede valer.&lt;br /&gt;
&lt;br /&gt;
Eso si, como ejercicio de programación ha estado realmente bien y me he permitido ver por encima como funcionan los árboles de expresión.&lt;br /&gt;
Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/3355942112878674973/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/07/entity-framework-y-el-borrado-de_04.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/3355942112878674973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/3355942112878674973'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/07/entity-framework-y-el-borrado-de_04.html' title='Entity Framework y el borrado de entidades (II) - usando lambda y árboles de expresión'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTcFRlSqAd5z09IhWBdJ5h-Velmf7_T9-2JW2R3o039ETCaNQb7DBFlx0td-ImxVvvoivYWPLypbdKmLlqicDnXiydSy07SDBruNoGoGK7MH2nL6adLAITDfgLBWrT1jC2CzS4DO_gzVE/s72-c/estadisticas.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-4405585351311054183</id><published>2012-07-03T14:11:00.003+01:00</published><updated>2012-07-03T14:11:26.753+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="csharp"/><category scheme="http://www.blogger.com/atom/ns#" term="entity framework"/><title type='text'>Entity Framework y el borrado de entidades (I)</title><content type='html'>A la hora de borrar entidades en Entity Framework nos damos cuenta que podemos actuar de dos maneras diferentes sobre todo si tenemos en cuenta factores como el número de consultas que tenemos que&amp;nbsp;lanzar contra nuestra base de datos.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Borrado de entidades por la clave primaria&lt;/b&gt;&lt;br /&gt;
Quizás es la forma más natural de realizar un borrado aunque no por ello es la única.&amp;nbsp;Supongamos&amp;nbsp;que tenemos la siguiente entidad POCO con la cual hemos montado nuestra base de datos a través de &lt;a href=&quot;http://smarrerof.blogspot.com.es/2012/04/entity-framework-code-first-fluent-api.html&quot; target=&quot;_blank&quot;&gt;Code First&lt;/a&gt;.&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public class Bar
{
  public int IdBar { get; set; }
  public string Description { get; set; }
  public int IdState { get; set; }
}&lt;/pre&gt;
El código para borrar una entidad por su clave primera podría ser algo así&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;private void DeleteByID(int idBar)
{
  using (DataContext context = new DataContext()) {
    Bar bar = context.Bar.Where(m =&amp;gt; m.IdBar == idBar).SingleOrDefault();
    context.Bar.Remove(bar);
    context.SaveChanges();
  }
}&lt;/pre&gt;
¿Sencillo verdad? La verdad es que si, aunque si somos un poco curiosos o simplemente sabemos lo que estamos haciendo y usamos el SQL Server Profiler veremos que la ejecución de ese código tan simple genera estas dos consultas&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;exec sp_executesql N&#39;SELECT TOP (2) 
[Extent1].[IdBar] AS [IdBar], 
[Extent1].[Description] AS [Description], 
[Extent1].[IdState] AS [IdState]
FROM [dbo].[Bar] AS [Extent1]
WHERE [Extent1].[IdBar] = @p__linq__0&#39;,N&#39;@p__linq__0 int&#39;,@p__linq__0=1&lt;/pre&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;exec sp_executesql N&#39;delete [dbo].[Bar]
where ([IdBar] = @0)&#39;,N&#39;@0 int&#39;,@0=1&lt;/pre&gt;
O sea, que estamos lanzando dos consultas contra nuestra base de datos para simplemente hacer un borrado. Esto desde mi punto de vista es un poco absurdo, aunque menos mal que con un pequeño truco podemos resolver este pequeño&amp;nbsp;inconveniente. El truco consiste en &lt;a href=&quot;http://msdn.microsoft.com/es-es/library/dd487214&quot; target=&quot;_blank&quot;&gt;adjuntar&lt;/a&gt; a nuestro contexto una entidad con la clave que queramos borrar, luego la borramos y grabamos los cambios. Con esto se&amp;nbsp;lanzará&amp;nbsp;la consulta de borrado con la información de la clave que deseamos borrar. El código para esto es el siguiente&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;private void DeleteByID(int idBar)
{
  using (DataContext context = new DataContext())
  {
    Bar bar = new Bar() { IdBar = idBar };
    context.Bar.Attach(bar);
    context.Bar.Remove(bar);
    context.SaveChanges();
  }
}&lt;/pre&gt;
Si usamos el SQL Profiler con este método veremos que tan solo se ejecuta esta consulta&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;exec sp_executesql N&#39;delete [dbo].[Bar]
where ([IdBar] = @0)&#39;,N&#39;@0 int&#39;,@0=1&lt;/pre&gt;
Como vemos, con un pequeño cambio hemos podido resolver de una manera fácil el problema de rendimiento que podríamos tener si hacemos muchos borrados en nuestra aplicación.&lt;br /&gt;
&lt;br /&gt;
En el próximo artículo trataré el borrado de registros cuando no estamos borrando por la clave primaria y donde una vez más el número de accesos a la base de datos puede ser un factor muy importante a tener en cuenta.&lt;br /&gt;
&lt;br /&gt;
Happy codding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/4405585351311054183/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/07/entity-framework-y-el-borrado-de.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/4405585351311054183'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/4405585351311054183'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/07/entity-framework-y-el-borrado-de.html' title='Entity Framework y el borrado de entidades (I)'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-1954499256173153754</id><published>2012-06-29T06:59:00.004+01:00</published><updated>2012-07-03T13:33:30.955+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="csharp"/><title type='text'>Cuidado con los redondeos porque puedes perder algún céntimo</title><content type='html'>Hoy voy a hablar sobre uno de esos fallos que te puede volver loco toda una mañana e incluso hacerte perder los papeles, sobre todo al final cuando te das cuenta del fallo.&lt;br /&gt;
&lt;br /&gt;
En esta ocasión la cosa va de redondeos de importes de facturas así que lo primero que haremos es buscar como se redondea los valores en euors. Según la sección 3, artículo 11 de la ley 46/1998, de 17 de diciembre (consultar &lt;a href=&quot;http://noticias.juridicas.com/base_datos/Admin/l46-1998.html#c2s3&quot; target=&quot;_blank&quot;&gt;aquí&lt;/a&gt;), sobre la introducción del euro&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Uno. En los importes monetarios que se hayan de abonar o contabilizar, cuando se lleve a cabo una operación de redondeo después de una conversión a la unidad euro, &lt;b&gt;deberán redondearse por exceso o por defecto al céntimo más próximo&lt;/b&gt;. Los importes monetarios que se hayan de abonar o contabilizar y se conviertan a la unidad monetaria peseta deberán redondearse por exceso o por defecto a la peseta más próxima. &lt;b&gt;En caso de que al aplicar el tipo de conversión se obtenga una cantidad cuya última cifra sea exactamente la mitad de un céntimo o de una peseta, el redondeo se efectuará a la cifra superior&lt;/b&gt;.
&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
O sea que debemos redondear a dos decimales al&amp;nbsp;céntimo&amp;nbsp;más próximo y en caso que el tercer decimal sea 5 debemos redondear al alza.&amp;nbsp;En base a esto haremos unas pruebas para ver el resultado&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;decimal d1;
decimal d2;

d1 = 123.472m;
d2 = Math.Round(d1, 2);
Print(d1, d2);

d1 = 123.478m;
d2 = Math.Round(d1, 2);
Print(d1, d2);

d1 = 123.475m;
d2 = Math.Round(d1, 2);
Print(d1, d2);
&lt;/pre&gt;
La salida de este programa es la siguiente
&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;Valor: 123,472
Valor redondeado: 123,47
---
Valor: 123,478
Valor redondeado: 123,48
---
Valor: 123,475
Valor redondeado: 123,48&lt;/pre&gt;
Como vemos todo funciona correctamente pero vamos a usar el valor 123,465 que según la ley debería ser redondeado a 123,47.&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;d1 = 123.465m;
d2 = Math.Round(d1, 2);
Print(d1, d2);&lt;/pre&gt;
Y la salida sería&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;Valor: 123,465
Valor redondeado: 123,46&lt;/pre&gt;
Si nos fijamos, vemos que el valor obtenido no es el que esperamos, y con este error nos tropezamos el otro día. Estabamos convencidos que el código estaba bien, ya que la función &lt;a href=&quot;http://msdn.microsoft.com/es-es/library/system.math.round(v=vs.80).aspx&quot; target=&quot;_blank&quot;&gt;Math.Round&lt;/a&gt;&amp;nbsp;hace el redondeando al alza en caso de ser un cinco. Tras mucho darle vueltas al asunto y algun que otro &quot;me cago en todo&quot;, nos dio por leernos con detalle la ayuda del método &lt;b&gt;Round&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
El valor devuelto por el método &lt;b&gt;Math.Round&lt;/b&gt; es &quot;&lt;i&gt;el número más próximo a d con una precisión igual a decimals. Si d se encuentra entre dos números, uno de los cuales es par y el otro es impar, se devuelve el número par. Si la precisión de d es menor que decimals, se devuelve d sin modificar.&lt;/i&gt;&quot;&lt;br /&gt;
&lt;br /&gt;
Vaya, ¿y esto?, para mi que el método &lt;b&gt;Math.Round&lt;/b&gt; no hacía esto, pero por lo que parece esto lo ha hecho de siempre así que la memoria nos ha gastado una mala pasada. Para que el redondeo sea el esperado debemos usar otra &lt;a href=&quot;http://msdn.microsoft.com/es-es/library/ms131275(v=vs.80)&quot; target=&quot;_blank&quot;&gt;sobrecarga&lt;/a&gt;&amp;nbsp;de dicho método, en la que podemos indicar que tipo de redondeo queremos usar, quedando nuestro código así&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;d1 = 123.465m;
d2 = Math.Round(d1, 2, MidpointRounding.AwayFromZero);
Print(d1, d2);&lt;/pre&gt;
Obteniendo la siguiente salida&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;Valor: 123,465
Valor redondeado: 123,47&lt;/pre&gt;
Así que, cuidado con los redondeos no sea que nos llevemos un susto en la facturación a final de año.&lt;br /&gt;
&lt;br /&gt;
Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/1954499256173153754/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/06/cuidado-con-los-redondeos-porque-puedes.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/1954499256173153754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/1954499256173153754'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/06/cuidado-con-los-redondeos-porque-puedes.html' title='Cuidado con los redondeos porque puedes perder algún céntimo'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3057613996558002471.post-3982342110198202244</id><published>2012-06-20T13:36:00.001+01:00</published><updated>2012-06-20T13:36:49.462+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="csharp"/><title type='text'>Validar el formato de una imagen (no me mientas con el formato) con C#</title><content type='html'>De verdad que hay veces en la que es mejor estarse callados porque si hablas puedes abrir &lt;a href=&quot;http://es.wikipedia.org/wiki/La_caja_de_Pandora&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;&lt;i&gt;La caja de Pandora&lt;/i&gt;&lt;/a&gt; y al final terminarás muy pero que muy mal.&lt;br /&gt;
&lt;br /&gt;
Toda esta historia comienza con un simple FileUpload que permite al usuario subir una imagen. En principio esto no debería dar ningún problema, es algo que se encuentra perfectamente documento en Internet y en menos de 2 minutos lo tienes montado en tu aplicación. El problema surge cuando a alguien se le ocurre hacer la siguiente pregunta, ¿qué pasa si no suben una imagen, o sea, si&amp;nbsp;algún&amp;nbsp;avispado coge un ejecutable y le cambia la extensión a por ejemplo, jpg? La verdad es que mis conocimientos sobre seguridad no llegan a tanto y no se cuales serías las implicaciones reales sobre tal acción pero con semejante pregunta ya tenemos el&amp;nbsp;lío&amp;nbsp;montado así que, toca hacer un sistema para comprobar que la imagen que el usuario ha subido es realmente la imagen que dice ser.&lt;br /&gt;
&lt;br /&gt;
Lo primero es preguntarnos cuales son los formatos gráficos que vamos a admitir, lo cual, es una mala pregunta porque la respuesta fue, todos. Eso es imposible así que, vamos a limitarlo a 3 o 4, así que la cosa quedó en los más utilizados, esto es, jpeg, gif, png y bmp.&lt;br /&gt;
&lt;br /&gt;
Para esto podríamos hacer uso del objeto &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.drawing.image.aspx&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Image&lt;/a&gt;&amp;nbsp;que nos da .NET, pero alguien (y no soy yo) se le metieron en la cabeza estás dos cosas&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Usar el objeto Image &lt;b&gt;es poco eficiente&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;Referenciar a System.Drawing en la capa de negocio &lt;b&gt;es poco elegante&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
De todas formas aquí está como podría ser este código (por si alguien quiere usarlo)&lt;/div&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public bool validateImage(byte[] bytes)
{
  try 
  {
    Stream stream = new MemoryStream(bytes);
    using(Image img = Image.FromStream(stream))
    {
      if (img.RawFormat.Equals(ImageFormat.Bmp) ||
          img.RawFormat.Equals(ImageFormat.Gif) ||
          img.RawFormat.Equals(ImageFormat.Jpeg) ||
          img.RawFormat.Equals(ImageFormat.Png))
        return true;
    }
    return false;
  } 
  catch
  {
    return false;
  }
}&lt;/pre&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;Tras revisar un poco de documentación sobre estos formatos (la wikipedia es un lugar fantástico) llegamos a esta conclusión.&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;JPEG&lt;/b&gt;: Los primeros 4 bytes son FF D8 FF E0 (aunque parece que lo realmente seguro son los dos primeros bytes, ya que por ejemplo algunas cámaras Canon ponen FF E1 en el tercer y cuatro byte).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GIF&lt;/b&gt;: Los primeros 6 bytes son siempre &quot;GIF87a&quot; o &quot;GIF89a&quot;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PNG&lt;/b&gt;: Los primeros 8 bytes son 89 50 4E 47 0D 0A 1A 0A.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BMP&lt;/b&gt;: Los primeros 2 bytes son 42 4D.&lt;/li&gt;
&lt;/ul&gt;
Con esta información ya nos podemos poner manos a la obra. Para realizar las validaciones implementamos una pequeña&amp;nbsp;factoría&amp;nbsp;de validadores de imágenes ya que después de esto vinieron más cosas, y al final lo mejor fue encapsular todo el comportamiento específico de cada imagen en un clase (como se debería hacer siempre, ¿no?).&lt;br /&gt;
Nuestra interface para la validación del formato&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public interface IImageValidator
{
  byte[] Content { get; set; }
  bool IsValid();
}&lt;/pre&gt;
Nuestra factoría de interfaces&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public static IImageValidator Create(string extension, byte[] content)
{
  switch (extension.ToUpper())
  {
    case &quot;BMP&quot;:
      return new BMPImageValidator() { Content = content };
    case &quot;GIF&quot;:
      return new GIFImageValidator() { Content = content };
    case &quot;JPG&quot;:
    case &quot;JPEG&quot;:
      return new JPEGImageValidator() { Content = content };
    case &quot;PNG&quot;:
      return new PNGImageValidator() { Content = content };
    default:
      throw new Exception(string.Format(&quot;Format &#39;{0}&#39; not supported&quot;, extension));
  }
}&lt;/pre&gt;
Y por último como sería el validador para el caso de un fichero jpg&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;public class JPEGImageValidator : IImageValidator
{
  #region IImageValidator

  public byte[] Content { get; set; }

  public bool IsValid()
  {
    byte[] magicNumber = { 0xFF, 0xD8 };   
    return (Content.Take(2).ToArray() == magicNumber);
  }

  #endregion
}&lt;/pre&gt;
Para usar el validador tan solo debemos hacer lo siguiente&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;byte[] imageJPG = System.IO.File.ReadAllBytes(&quot;test-jpg.jpg&quot;);
IImageValidator validator = ImageValidatorFactory.Create(&quot;jpg&quot;, imageJPG);
bool isValid = validator.IsValid();
&lt;/pre&gt;
Para la prueba estoy cargando la imagen desde un fichero. Si queremos usarlo en un entorno web (MVC) podemos hacer lo siguiente&lt;br /&gt;
&lt;pre class=&quot;csharp&quot; name=&quot;code&quot;&gt;string extension = string.Empty;
if (file.FileName.LastIndexOf(&#39;.&#39;) &amp;gt; 0)
  extension = file.FileName.Substring(file.FileName.LastIndexOf(&#39;.&#39;) + 1);       
MemoryStream memoryStream = new MemoryStream();
file.InputStream.CopyTo(memoryStream);
byte[] content = memoryStream.ToArray();

IImageValidator validator = ImageValidatorFactory.Create(extension, content);
bool isValid = validator.IsValid();&lt;/pre&gt;
Respecto a la eficiencia de los métodos, he modificado el método validateImage para que en vez de validar un byte[] también valide un Stream, para ahorrarnos esta conversión y así ser más justos en la comparación. Los resultados son realmente demoledores&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;background-color: white;&quot;&gt;validateImage (byte[]): 5601 ms.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: white;&quot;&gt;validateImage (stream): 5157 ms.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: white;&quot;&gt;ImageValidatorFactory: 4 ms.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Así que realmente el uso de la clase Image es un factor a tener en cuenta en caso que trabajemos de manera masiva con imágenes.&lt;br /&gt;
&lt;br /&gt;
Viendo estos números puede que quede justificado hacer nuestros propios validadores de imágenes aunque para otras tareas puede que no quede tan justificado sobre todo teniendo en cuenta los mil y un detalles que hay que tener en cuenta cuando trabajamos con este tipo de ficheros a bajo nivel.&lt;br /&gt;
&lt;br /&gt;
Happy coding!</content><link rel='replies' type='application/atom+xml' href='http://smarrerof.blogspot.com/feeds/3982342110198202244/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://smarrerof.blogspot.com/2012/06/validar-el-formato-de-una-imagen-no-me.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/3982342110198202244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3057613996558002471/posts/default/3982342110198202244'/><link rel='alternate' type='text/html' href='http://smarrerof.blogspot.com/2012/06/validar-el-formato-de-una-imagen-no-me.html' title='Validar el formato de una imagen (no me mientas con el formato) con C#'/><author><name>Sergio</name><uri>http://www.blogger.com/profile/08385685095759720185</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4QMHmKyhQlhMqk-lpnC7NbuQ9RfP9DcwpknNtGa_5aGmgizL0f1syKPt5u8fM1Cpq_Gg2n-QiApyyC_N39Jj0f4mYgj1TdiRLKNfIY5zopcM7Msy7GKY_J4CqcxhBDQ/s220/contraluz.120.jpg'/></author><thr:total>0</thr:total></entry></feed>