tag:blogger.com,1999:blog-30335484148316373552009-07-14T23:16:05.568-03:00zPodEl blog amigo del Nerd modernoZaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.comBlogger81125tag:blogger.com,1999:blog-3033548414831637355.post-9623882136523216722009-07-14T23:13:00.002-03:002009-07-14T23:16:05.590-03:00Monos y Manzanas: Key Value Coding y Configuración<p>Hacia el final de la entrega anterior de <em>Monos y Manzanas</em> estuve contando sobre como utilizar los bindings de Cocoa con Monobjc. En el capítulo final de esta serie de posts veremos como es posible agilizar la implementación de clases que utilicen <em>Key Value Coding</em> (KVC de ahora en mas) desde .NET y como agregar un panel de preferencias para modificar la configuración de la aplicación y que la misma sea persistida de forma automática.</p> <p><em>Ante todo, fe de erratas: una persona del equipo de MonobjC con la cual me contacté, me acalró que no es necesario crear una instancia que nadie usa de NSAutoReleasePool en el bootstrapping de la aplicación, ya que eso se hace automáticamente.</em></p> <p>En el último ejemplo mostrado, cada vez que se quería implementar una propiedad que pudiese ser utilizada para los bindings con KVC era necesario crear los setters y getters, indicarles que iban a ser llamados como mensajes de ObjectiveC y llamar a las notificaciones de cambios de propiedad. <br />Para no tener que hacer esto por cada propiedad que queramos exponer al runtime de ObjectiveC, crearemos un nuevo atributo el cual <em>indique</em> que esa propiedad podrá ser utilizada con KVC:</p> <pre>using System;<br /><br />namespace zPod.Objc<br />{<br /> public class KeyValueCodingAttribute : Attribute<br /> {<br /> public KeyValueCodingAttribute (string propertyName)<br /> {<br /> PropertyName = propertyName;<br /> }<br /> <br /> public string PropertyName<br /> {<br /> get;<br /> set;<br /> }<br /> }<br />}</pre><br /><p>Teniendo esto, las propiedades que querramos exponer se verán así:</p><br /><pre>[KeyValueCoding("modelo")]<br />public BrowserModel Modelo<br />{<br /> get;<br /> set;<br />}</pre><br /><p>Muy lindo hasta ahora pero... ¿Como le indicamos al runtime de ObjectiveC que deberá tomar la propiedad "modelo" al intentar llamar al mensaje "modelo" o "setModelo:"? Simple, sobreescribiendo el llamado a los mensajes "setValue:forUndefinedKey:" y "valueForUndefinedKey"</p><br /><pre>[ObjectiveCMessage("setValue:forUndefinedKey:")]<br />public override void SetValueForUndefinedKey (Id val, NSString key)<br />{<br /> this.ResolveSetValueForUndefinedKey(val, key);<br />}<br /> <br />[ObjectiveCMessage("valueForUndefinedKey:")]<br />public override Id ValueForUndefinedKey (NSString key)<br />{<br /> return this.ResolveValueForUndefinedKey(key);<br />}</pre><br /><p>Al no encontrar una clave definida, Cocoa avisa a la clase que se intento leer o dar valor a la clave utilizando estos mensajes.</p><br /><p>En estas implementaciones se está llamando a los métodos <em>ResolveSetValueForUndefinedKey </em>y <em>ResolveValueForUndefinedKey</em>. Los mismos son extension methods creados para la clase <em>NSObject </em>que resuelven cual es la propiedad que deberá ser devuelta o modificada utilizando reflection para saber si tienen el atributo definido anteriormente. El código de estos métodos se incluye dentro de los fuentes de este ejemplo.</p><br /><hr /><br /><p>Hacia el final de la entrega anterior de <em>Monos y Manzanas</em> comenté que Cocoa proveía un controller especial llamado <em>NSUserDefaultsController</em> que permite guardar automáticamente las preferencias del usuario.<br />Ahora vamos a ver como crear un nuevo panel de preferencias donde configurar la URL Home de nuestro browser.</p><br /><p>Volviendo al Interface Builder, agregamos un nuevo NSPanel y le agregamos un TextField para ingresar la URL Home</p><br /><p><a href="http://lh5.ggpht.com/_TEAv5Jw76vg/Sl067tmhupI/AAAAAAAAAWg/7iny61_lM88/s1600-h/Picture%201%5B3%5D.png"><img title="Picture 1" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="88" alt="Picture 1" src="http://lh3.ggpht.com/_TEAv5Jw76vg/Sl068KDxcDI/AAAAAAAAAWk/_qcxNbXNoew/Picture%201_thumb%5B1%5D.png?imgmax=800" width="378" border="0" /></a> </p><br /><p>Para poder abrir el panel desde el menu de preferencias, conectamos la opción <em>Preferences...</em> del menú con el panel creado, asociándolo a la acción <em>makeKeyAndOrderFront:</em>.</p><br /><p><a href="http://lh3.ggpht.com/_TEAv5Jw76vg/Sl06_HyFsNI/AAAAAAAAAWo/AXkip_OhlLg/s1600-h/Picture%203%5B3%5D.png"><img title="Picture 3" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="388" alt="Picture 3" src="http://lh4.ggpht.com/_TEAv5Jw76vg/Sl07Cc99WJI/AAAAAAAAAWs/Q2oq1wdnstc/Picture%203_thumb%5B1%5D.png?imgmax=800" width="385" border="0" /></a> </p><br /><p>Dado que se necesita únicamente una instancia de este panel, lo configuramos como se muestra en la siguiente imagen. Lo mas importante es desmascar las opciones <em>Released When Closed</em> y <em>Visible at launch</em> para que no se muestre al incio, pero que al cerrar la ventana solamente se oculte y no se destruya el objeto.</p><br /><p><a href="http://lh6.ggpht.com/_TEAv5Jw76vg/Sl07DnlWGlI/AAAAAAAAAWw/MkIE6B0yt9E/s1600-h/Picture%202%5B5%5D.png"><img title="Picture 2" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="531" alt="Picture 2" src="http://lh3.ggpht.com/_TEAv5Jw76vg/Sl07Et2_rlI/AAAAAAAAAW0/LlalSVZYflo/Picture%202_thumb%5B3%5D.png?imgmax=800" width="229" border="0" /></a> </p><br /><p>Creamos el binding para el <em>value</em> del TextField, conectándolo con la instancia de <em>SharedUserDefaultsController</em>, utilizando la clave <em>values</em> y el model key path <em>homePage</em>.<br />Al utilizar este controller, los valores conectados serán persistidos automáticamente.</p><br /><p><a href="http://lh6.ggpht.com/_TEAv5Jw76vg/Sl07F_YJ-CI/AAAAAAAAAW4/_nUjnxw3OlY/s1600-h/Picture%204%5B3%5D.png"><img title="Picture 4" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="558" alt="Picture 4" src="http://lh5.ggpht.com/_TEAv5Jw76vg/Sl07HC4_qiI/AAAAAAAAAW8/qmWUXE_y_34/Picture%204_thumb%5B1%5D.png?imgmax=800" width="232" border="0" /></a> </p><br /><p>Como último paso dentro del Interface Builder, agregamos un nuevo boton para ir a la home, agregamos una nueva acción llamada <em>goHome:</em> al <em>BrowserController</em> y los asociamos de la misma manera que el boton <em>Go</em>.</p><br /><p><a href="http://lh5.ggpht.com/_TEAv5Jw76vg/Sl07H114X1I/AAAAAAAAAXA/P-J9eJFD3yQ/s1600-h/Picture%205%5B3%5D.png"><img title="Picture 5" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="287" alt="Picture 5" src="http://lh5.ggpht.com/_TEAv5Jw76vg/Sl07IUWa2GI/AAAAAAAAAXE/34yStQRQLD0/Picture%205_thumb%5B1%5D.png?imgmax=800" width="425" border="0" /></a> </p><br /><p>Volviendo a C#, Dentro del código del <em>BrowserController</em>, modificamos el método <em>AwakeFromNib</em> y agregamos el método que responda al mensaje <em>goHome:</em>, para que al iniciar la aplicación vaya a la URL definida como home y, en caso de no haber nada, definirle un valor default (recuenden que en <em>_userDefaults</em> tenemos guardada una instancia de <em>SharedUserDefaultsController</em>):</p><br /><pre>[ObjectiveCMessage("goHome:")]<br />public void GoHome(Id sender)<br />{<br /> NSString home = _userDefaults.ValueForKeyPath("values.homePage");<br /> this.Modelo.WillChangeValueForKey("url");<br /> this.Modelo.Url = home;<br /> this.Modelo.DidChangeValueForKey("url");<br /> Browse(sender);<br />}<br /><br />[ObjectiveCMessage("browse:")]<br />public void Browse(Id sender)<br />{<br /> NSString url = this.Modelo.Url;<br /> browser.MainFrameURL = url;<br /> _userDefaults.SetValueForKeyPath("CocoaBrowser - " + url, "values.title"); <br />}<br /><br />[ObjectiveCMessage("awakeFromNib")]<br />public void AwakeFromNib ()<br />{<br /> NSString home = _userDefaults.ValueForKeyPath("values.homePage");<br /> if (home == null)<br /> {<br /> _userDefaults.SetValueForKeyPath(new NSString("http://zPod.com.ar"), "values.homePage");<br /> }<br /> <br /> GoHome(null);<br />}</pre><br /><p>Listo! Ahora a compilar y a disfrutar de su nuevo browser con botón de Home <em>para Mac hecho en .NET</em>!</p><br /><p><a href="http://lh5.ggpht.com/_TEAv5Jw76vg/Sl07LOtfAAI/AAAAAAAAAXI/1YCbIkjyh28/s1600-h/Picture%206%5B4%5D.png"><img title="Picture 6" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="352" alt="Picture 6" src="http://lh3.ggpht.com/_TEAv5Jw76vg/Sl07MqofNLI/AAAAAAAAAXM/PvRNewsjymc/Picture%206_thumb%5B2%5D.png?imgmax=800" width="451" border="0" /></a> </p><br /><p>Con esto queda finalizada la serie de posts: <em>Monos y Manzanas</em>. El código completo lo pueden bajar de <a href="http://www.mediafire.com/download.php?uwyx5ommlmz" target="_blank">aca</a>.</p><br /><br /><p>Hasta la próxima!<br /><strong>Zaiden</strong></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-962388213652321672?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com0tag:blogger.com,1999:blog-3033548414831637355.post-7484600311321912352009-07-12T11:05:00.003-03:002009-07-12T16:13:15.954-03:00Monos y Manzanas: Binding entre la UI y el Modelo<p>En el último post expliqué como hacer una aplicación sencilla para Mac cuya UI estaba hecha con Interface Builder, y el resto de la <em>plomería de fondo</em> utilizaba C#, gracias a <em>Mono</em> y el bridge <em>Monobjc</em>. </p> <p>Dada la <em>extrema</em> simplicidad de nuestro <em>CocoaBrowser</em>, hubieron algunos conceptos que escaparon al ejemplo inicial. </p> <p>En esta nueva entrega de <em>Monos y Manzanas</em> veremos como hacer uso del <em>binding</em> provisto por <em>Cocoa</em> y el <em>Interface Builder</em> para <em>conectar</em> nuestra interfaz gráfica al Modelo de nuestra aplicación.</p> <p>Por ahora, definiremos una nueva clase <em>BrowserModel</em>, la cual representará el “modelo” de nuestra apliación de juguete.</p> <pre>public class BrowserModel<br />{<br /> private string _url;<br /> public string GetUrl()<br /> {<br /> return _url;<br /> }<br /><br /> public void SetUrl(string newUrl)<br /> {<br /> _url = newUrl;<br /> }<br />}</pre><br /><br /><p>Posiblemente se pregunten: <em>Por qué la propiedad esta definida con metodos Get y Set, en vez se ser una propiedad “normal” de C#, al estilo “public string Url { get; set'; }”? </em><br /><br />Es por un requerimiento del bridge con Objective-C y el binding con la UI, pero vamos a verlo bien mas adelante.</p><br /><p>La idea es que lo que usuario tipee dentro del TextField utilizado para ingresar la URL de nuestro browser actualice automáticamente nuestro modelo y, en caso de actualizar el modelo desde otro lugar, se actualice automáticamente el TextField.</p><br /><p>Para poder hacer esto, agregaremos un nuevo campo a la clase BrowserController que nos de acceso al modelo, y lo haremos visible para el bridge, con los siguientes getter y setter:</p><br /><pre>[ObjectiveCClass]<br />public class BrowserController : NSObject<br />{<br /> //<br /> // Mucho codigo antes...<br /> //<br /><br /> private BrowserModel _modelo = new BrowserModel();<br /><br /> [ObjectiveCMessage(&quot;modelo&quot;)]<br /> public BrowserModel getModelo()<br /> {<br /> return _modelo;<br /> }<br /><br /> [ObjectiveCMessage(&quot;setModelo:&quot;)]<br /> public void setModelo(BrowserModel nuevoModelo)<br /> {<br /> WillChangeValueForKey(&quot;modelo&quot;);<br /> _modelo = nuevoModelo;<br /> DidChangeValueForKey(&quot;modelo&quot;);<br /> }<br /><br /> //<br /> // Mucho codigo despues...<br /> //<br /><br />}</pre><br /><p>Esta forma de crear los campos permite a ObjectiveC utilizar la clase con algo conocido como <em>Key Value Coding</em>, accediendo a ciertas propiedades de nuestra clase como si fuesen pares Clave - Valor, tanto para leer como para escribir. <br /><br />Los métodos <em>WillChangeValueForKey</em> y <em>DidChangeValueForKey</em> permiten avisarle a la UI que hubo un cambio en el valor la propiedad.</p><br /><p>Para que las propiedades de la clase <em>BrowserModel</em> sean accesibles de la misma manera, las decoramos de forma similar, quedando como resultado:</p><br /><pre>[ObjectiveCClass]<br />public class BrowserModel : NSObject<br />{<br /> // Constructores requeridos por NSObject<br /> public BrowserModel()<br /> {<br /> }<br /> <br /> public BrowserModel (IntPtr nativePointer) : base(nativePointer)<br /> {<br /> }<br /><br /> private string _url;<br /><br /> [ObjectiveCMessage(&quot;url&quot;)]<br /> public string GetUrl()<br /> {<br /> return _url;<br /> }<br /> <br /> [ObjectiveCMessage(&quot;setUrl:&quot;)]<br /> public void SetUrl(string newUrl)<br /> {<br /> WillChangeValueForKey(&quot;url&quot;);<br /> _url = newUrl;<br /> DidChangeValueForKey(&quot;url&quot;);<br /> }<br />}</pre><br /><p>Como pueden ver, es requisito agregar el atributo <em>[ObjectiveCClass]</em> y hacer heredar la clase de <em>NSObject</em> (o algún hijo) para que la misma sea visible desde ObjectiveC. Al hacer esto, deberán agregar los dos constructores indicados en el código.</p><br /><p>Dado que ahora el URL a navegar será indicado por las propiedades del modelo, podemos sacar la referencia al TextField del <em>BrowserController</em> y modificar el metodo Browse de la siguiente manera:</p><br /><pre>[ObjectiveCClass]<br />public class BrowserController : NSObject<br />{<br /> //<br /> // Mucho codigo antes...<br /> //<br /><br /> [ObjectiveCMessage(&quot;browse:&quot;)]<br /> public void Browse(Id sender)<br /> {<br /> string url = this.fModelo.getUrl();<br /> browser.MainFrameURL = url;<br /> }<br /><br /> //<br /> // Mucho codigo despues...<br /> //<br /><br />}</pre><br /><p>Con esto listo, solo resta hacer los bindings propiamente dichos en el Interface Builder.</p><br /><p>El primer paso será agregar un <em>ObjectController</em> desde la <em>Library</em>. Este tipo de controller nos permite hacer binding facilmente a un objeto concreto del modelo. En caso de querer hacer binding contra Arrays, Diccionarios y otros tipos de datos, existen controllers mas apropiados.</p><br /><p><a href="http://lh6.ggpht.com/_TEAv5Jw76vg/Slntex3VJWI/AAAAAAAAAWA/2J0S8ytZyDE/s1600-h/Picture%201%5B5%5D.png"><img title="Picture 1" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="532" alt="Picture 1" src="http://lh3.ggpht.com/_TEAv5Jw76vg/SlntgVHI7gI/AAAAAAAAAWE/LwfpePgLhhI/Picture%201_thumb%5B3%5D.png?imgmax=800" width="248" border="0" /></a> </p><br /><p>Dentro de los atributos del <em>ObjectController</em>, agregar una nueva clave llamada “url”, la cual usaremos como nexo entre el modelo y la UI.</p><br /><p><a href="http://lh3.ggpht.com/_TEAv5Jw76vg/Slntg9UCvfI/AAAAAAAAAWI/5HbXUrxMM2k/s1600-h/Picture%202%5B4%5D.png"><img title="Picture 2" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="597" alt="Picture 2" src="http://lh4.ggpht.com/_TEAv5Jw76vg/SlnthrLA75I/AAAAAAAAAWM/vvjrgvLzXuY/Picture%202_thumb%5B2%5D.png?imgmax=800" width="252" border="0" /></a> </p><br /><p>Dentro de los bindings del <em>ObjectController</em>, indicamos que el <em>Controller Content</em> debe hacer binding con el <em>BrowserController</em>, utilizando como <em>Model Key Path</em> “modelo”. Esto hará referencia a la propiedad <em>modelo</em> que creamos – e hicimos visible con setter y getter para ObjectiveC – dentro de la clase creada en C#.</p><br /><p><a href="http://lh6.ggpht.com/_TEAv5Jw76vg/SlntidB_KRI/AAAAAAAAAWQ/ZceZIbvuuac/s1600-h/Picture%203%5B3%5D.png"><img title="Picture 3" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="612" alt="Picture 3" src="http://lh6.ggpht.com/_TEAv5Jw76vg/SlntjsGuFQI/AAAAAAAAAWU/TggQGUdpF0Q/Picture%203_thumb%5B1%5D.png?imgmax=800" width="254" border="0" /></a> </p><br /><p>Finalmente, seleccionamos el TextField de la URL y dentro de la solapa de bindings indicamos que se deberá hacer el binding con el<em> ObjectController</em>, utilizando “selection” como <em>Controller Key y “url” como Model Key Path</em>. Para que el modelo se actualice <em>cada vez que se modifica </em>el TextField y no únicamente al terminar de editarlo cambiando el foco, deberemos marcar el check de “Continuosly Update Value”.</p><br /><p><a href="http://lh6.ggpht.com/_TEAv5Jw76vg/Slntkv_C5xI/AAAAAAAAAWY/CAom32P2cSg/s1600-h/Picture%204%5B3%5D.png"><img title="Picture 4" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="622" alt="Picture 4" src="http://lh6.ggpht.com/_TEAv5Jw76vg/SlntmMa45cI/AAAAAAAAAWc/TZ-1t2GXvqc/Picture%204_thumb%5B1%5D.png?imgmax=800" width="258" border="0" /></a> </p><br /><p>Como yapa, en esta versión de los fuentes, podrán ver como hacer binding contra una clase especial llamada <em>NSUserDefaultsController</em>, la cual nos permite mantener guardadas las preferencias del usuario haciendo binding contra las mismas. En este ejemplo se utiliza para guardar el titulo de la ventana de la aplicación, aunque su utilidad mas común es dentro de los paneles de preferencias.</p><br /><p>El código lo pueden bajar de <a href="http://www.mediafire.com/download.php?mghzgyn0y0y" target="_blank">aca</a>.</p><br /><p>Hasta la próxima!<br /><strong>Zaiden</strong></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-748460031132191235?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com0tag:blogger.com,1999:blog-3033548414831637355.post-43095386331688586972009-07-08T01:32:00.002-03:002009-07-08T08:47:22.420-03:00Monos y Manzanas: Como hacer aplicaciones Cocoa con .NET<p>Desde que soy usuario de OS X he intentado varias veces desarrollar alguna aplicación que pueda aprovechar todo el poder de la plataforma .NET y las delicias gráficas de las interfaces gráficas creadas con <strong>Cocoa </strong>y sus frameworks para Mac. </p> <p>La necesidad de utilizar .NET sobre el sistema operativo impulsado por <em>Steve Jobs </em>está cubierta desde hace un buen tiempo por la gente de <strong>Mono </strong>y su implementación multiplataforma del CLR y gran mayoría de las librerías incluidas en el <em>.NET Framework</em>. <br />El problema radicaba en como poder interactuar de forma simple y comoda con una UI hecha en Cocoa y no con el - <em>bastante sovietico </em>- port de <em>Windows.Forms </em>que incluye Mono, o con librerías graficas como <em>GTK </em>que se ven bastante <em>alienigenas</em> dentro de la Mac. </p> <p>Investigando un poco, encontré que existen varios proyectos que hacen de <em>bridge</em> entre el mundo de Mono<em> </em>y .NET y los frameworks provistos por Cocoa. <br />Inicialmente, utilicé la librería publicada en el mismo sitio de Mono: <strong>Cocoa#</strong>. El problema fue que, pese a su simplicidad, tenía demasiados problemas de performance y estabilidad, por lo que quedó descartada. </p> <p>Hace no mucho leí de otro bridge que, apartentemente, tiene bastante aceptación: <strong>Monobjc</strong>. Estas librerías permiten utilizar tanto una interfaz creada en Cocoa y sus frameworks desde una aplicación .NET como exponer - <em>con ciertas restricciones </em>- clases hechas en .NET dentro de una aplicación nativa hecha en Cocoa y ObjectiveC. </p> <p>En este caso voy a explicar, paso a paso, como crear una nueva aplicación que nos permita navegar por la web cuya (única) View esté desarrollada con Cocoa utilizando el <em>Interface Builder </em>y el Controller y (ausente) Model estén hechos en C#</p> <p><strong>Requerimientos</strong></p> <ul> <li>Mac OS X Leopard </li> <li>XCode + Interface Builder (se baja gratis de la página de apple) </li> <li>Bridge de Monobjc (<a href="http://www.monobjc.net">http://www.monobjc.net</a>) </li> <li>Mono Runtime y MonoDevelop (<a href="http://go-mono.com">http://go-mono.com</a>) </li> </ul> <p>Para empezar vamos a crear una nueva <strong>View </strong>utilizando <em>Interface Builder </em>(se recomienda tener al menos conocimientos básicos sobre como utilizar Interface Builder). </p> <p>Al abrir Interface Builder seleccionamos el template de <em>Cocoa Application</em></p> <p><a href="http://lh3.ggpht.com/_TEAv5Jw76vg/SlQhC61_SfI/AAAAAAAAAVI/cPJtRyHf98Y/s1600-h/1.%20NuevaApp%5B4%5D.png"><img title="1. NuevaApp" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="298" alt="1. NuevaApp" src="http://lh4.ggpht.com/_TEAv5Jw76vg/SlQhDkh1hYI/AAAAAAAAAVM/at31uQKYgD0/1.%20NuevaApp_thumb%5B2%5D.png?imgmax=800" width="373" border="0" /></a> </p> <p>Una vez creado el proyecto, podremos ver la ventana principal creada para la aplicación, su menú, el listado de objetos existentes, el inspector donde podrémos modificar propiedades de los controles y la librería de controles disponibles desde Cocoa</p> <p><a href="http://lh6.ggpht.com/_TEAv5Jw76vg/SlQhGy0qSoI/AAAAAAAAAVQ/P5Qa7GYtgVw/s1600-h/2.%20Empezar%5B3%5D.png"><img title="2. Empezar" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="257" alt="2. Empezar" src="http://lh6.ggpht.com/_TEAv5Jw76vg/SlQhIDtV80I/AAAAAAAAAVU/KfAH1XYYh1w/2.%20Empezar_thumb%5B1%5D.png?imgmax=800" width="385" border="0" /></a> </p> <p>En la librería de controles buscamos los controles de <em>WebView</em>, <em>TextField </em>y <em>Button </em>y los agregamos a la ventana, como se ve en la imagen. Pueden modificar las propiedades de estos controles en el inspector para permitirles ajustar su tamaño de acuerdo al resizing de la ventana.</p> <p><a href="http://lh6.ggpht.com/_TEAv5Jw76vg/SlQhIohTIuI/AAAAAAAAAVY/0jOWlNfw7jk/s1600-h/5.%20VentanaLista%5B3%5D.png"><img title="5. VentanaLista" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="262" alt="5. VentanaLista" src="http://lh3.ggpht.com/_TEAv5Jw76vg/SlQhJewB57I/AAAAAAAAAVc/0PZZa9lTcak/5.%20VentanaLista_thumb%5B1%5D.png?imgmax=800" width="387" border="0" /></a> </p> <p>Con la ventana lista, agregamos un nuevo <em>Object</em> a la ventana que contiene la lista de objetos disponibles, y cambiamos el nombre de su clase por <em>ObjectController</em>. Este será el objeto que represente al Controller que crearemos desde C# mas adelante.</p> <p><a href="http://lh5.ggpht.com/_TEAv5Jw76vg/SlQhKcBLC2I/AAAAAAAAAVg/wwRerb3DkQc/s1600-h/6.%20NuevoObject%5B4%5D.png"><img title="6. NuevoObject" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="384" alt="6. NuevoObject" src="http://lh3.ggpht.com/_TEAv5Jw76vg/SlQhLXNRb7I/AAAAAAAAAVk/7GoohU3Ko1k/6.%20NuevoObject_thumb%5B2%5D.png?imgmax=800" width="231" border="0" /></a> </p> <p>Dentro de las <em>actions</em> disponibles para el controller deberemos agregar "<em>browse:</em>" que corresponderá a la acción de iniciar la navegación del URL escrito en el <em>TextField </em>anterior. <br />De la misma manera, deberémos exponer los Outlets "<em>address</em>", "<em>window</em>" y "<em>browser</em>" como se muestra en la imagen, los cuales asociaremos al TextField, la ventana y el WebView.</p> <p><a href="http://lh4.ggpht.com/_TEAv5Jw76vg/SlQhMGgfB9I/AAAAAAAAAVo/4TvPaKNtIbI/s1600-h/7.%20PropiedadesController%5B4%5D.png"><img title="7. PropiedadesController" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="511" alt="7. PropiedadesController" src="http://lh4.ggpht.com/_TEAv5Jw76vg/SlQhNEOn5TI/AAAAAAAAAVs/PQYv6dk00X4/7.%20PropiedadesController_thumb%5B2%5D.png?imgmax=800" width="219" border="0" /></a> </p> <p>El último paso de esta parte será hacer el link entre las acciones y outlets definidos en el BrowserController y los controles creados dentro de la UI. Para hacer esto mantenemos apretada la tecla control y dibujamos una linea hacia cada uno de los controles. De esta manera aparecerá un menú para vincularlos hacia los <em>outlets </em>disponibles en el Controller. <br />De forma análoga se debe dibujar una linea desde el botón hacia el BrowserController, para asociar el click a la action "<em>browse:</em>" </p> <p>Para asegurarse de haber vinculado todo de forma correcta, al hacer click derecho sobre el BrowserController se deberá ver un panel similar a este:</p> <p><a href="http://lh6.ggpht.com/_TEAv5Jw76vg/SlQhPv1HxXI/AAAAAAAAAVw/r1NoPmw80fQ/s1600-h/8.%20BindingController%5B3%5D.png"><img title="8. BindingController" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="300" alt="8. BindingController" src="http://lh4.ggpht.com/_TEAv5Jw76vg/SlQhRTbmJOI/AAAAAAAAAV0/WI9krR2Wcjk/8.%20BindingController_thumb%5B1%5D.png?imgmax=800" width="359" border="0" /></a> </p> <p>Con la interfaz lista, guardamos la ventana como un nuevo archivo <strong>NIB </strong>(<em>ojo! guardar como NIB y NO como XIB!</em>). </p> <p>Ahora, a programar el controller y el <em>bootstrap </em>de la aplicación en C# <br />Para hacerlo, pueden utilizar cualquier IDE de su agrado. En particular, yo uso <strong>MonoDevelop</strong>. </p> <p>Deberémos crear un proyecto el cual referencie a las assemblies de <em>Monobjc</em>, <em>Monobjc.Cocoa</em> y <em>Monobjc.WebKit</em> ya que son las que utilizamos dentro de la interfaz. <br />Dentro del proyecto crearemos dos clases: la primera será el <em>bootstrap </em>de la aplicación y la segunda sera el <em>BrowserController </em></p> <p>Para hacer el bootstrap deberémos crear una clase muy similar al siguiente ejemplo:</p> <pre>using Monobjc;<br />using Monobjc.Cocoa;<br />using System;<br /><br />namespace zPod.CocoaBrowser<br />{<br /> public class Program<br /> {<br /> public Program ()<br /> {<br /> }<br /><br /> public static void Main (String[] args)<br /> {<br /> ObjectiveCRuntime.LoadFramework ("Cocoa");<br /> ObjectiveCRuntime.LoadFramework ("WebKit");<br /> <br /> ObjectiveCRuntime.Initialize ();<br /> NSApplication.Bootstrap ();<br /> <br /> NSAutoreleasePool pool = new NSAutoreleasePool();<br /> <br /> NSApplication.LoadNib ("MainWindow.nib");<br /> NSApplication.RunApplication ();<br /> }<br /> }<br />}</pre><br /><br /><p>Las primeras lineas del método Main cargan los frameworks de ObjectiveC que utilizaremos. En este caso "<em>Cocoa</em>" y "<em>WebKit</em>".<br /><br /><br />Luego de cargar los frameworks se inicializa el bridge con el runtime de ObjectiveC y se dispara la aplicación.<br /><br /><br />Como verán, antes de cargar el NIB se crea un nuevo <em>NSAutoreleasePool</em>. Esto sirve para evitar leaking por parte de <em>ObjectiveC</em>. </p><br /><br /><p>Finalmente llamamos al metodo <em>LoadNib</em>, el cual cargará la interfaz grafica creada anteriormente y lanzamos la aplicacion con el método <em>RunApplication</em>. </p><br /><br /><p>La creación del <em>BrowserController </em>es muy sencilla: en la misma hay que crear propiedades que corresponderán a los outlets definidos en la interfaz y metodos para atrapar las actions disparadas desde la misma. </p><br /><br /><p>Las clases marcadas con el atributo <em>[ObjectiveCClass]</em> serán expuestas al runtime de ObjectiveC. Las propiedades decoradas con el atributo <em>[ObjectiveCField]</em> representan los outlets y los métodos decorados con <em>[ObjectiveCMessage]</em> sirven para atrapar las actions disparadas por la View.</p><br /><br /><pre>using System;<br />using Monobjc;<br />using Monobjc.Cocoa;<br />using Monobjc.WebKit;<br /><br />namespace zPod.CocoaBrowser<br />{<br /> [ObjectiveCClass]<br /> public class BrowserController : NSObject<br /> {<br /> [ObjectiveCField]<br /> public NSTextField address;<br /> <br /> [ObjectiveCField]<br /> public WebView browser;<br /><br /> [ObjectiveCField]<br /> public NSWindow window;<br /><br /> public BrowserController ()<br /> {<br /> }<br /><br /> public BrowserController (IntPtr nativePointer) : base(nativePointer)<br /> {<br /> }<br /><br /> [ObjectiveCMessage("browse:")]<br /> public void Browse (Id sender)<br /> {<br /> string url = address.Cell.Title;<br /> <br /> browser.MainFrameURL = url;<br /> }<br /><br /> [ObjectiveCMessage("awakeFromNib")]<br /> public void AwakeFromNib ()<br /> {<br /> window.Title = "CocoaBrowser - zPod";<br /> }<br /> }<br />}</pre><br /><br /><p>En este ejemplo, se ve el método AwakeFromNib, el cual se ejecutará al finalizar de cargar la vista. En el mismo, seteamos el título de la ventana.<br /><br />Para atrapar la accion "browse", creamos un metodo con su correspondiente atributo y dentro del mismo cambiamos la URL del MainFrame del WebView. </p><br /><br /><p>Una vez listo esto, solo queda probar la aplicación.<br /><br />Según la documentación de Monobjc, se tendría que poder ejecutar un script de <em>NAnt</em> que proveen ellos y crear una estructura de directorios específica. Dado que eso no me está funcionando (por algún motivo <em>NAnt </em>no encuentra a <em>mono</em>) armé un pequeño script de bash que arma todo lo necesario para tener nuestra App empaquetada y lista para ejecutar. </p><br /><br /><p><a href="http://www.mediafire.com/download.php?mdutd4zlnjn" target="_blank">Aca</a> dejo para bajar esta aplicación de ejemplo como proyecto de MonoDevelop, el cual al compilarse dejará en el directorio bin/Debug todos los archivos necesarios para armar el paquete. Lo único que hay que hacer es, desde la consola, ir al directorio /bin/Debug del proyecto y ejecutar:</p><br /><br /><pre>./MakePackage CocoaBrowser</pre><br /><br /><p>Con esto se generará un nuevo paquete de aplicación ejecutable, cuyo resultado es:</p><br /><br /><p><a href="http://lh4.ggpht.com/_TEAv5Jw76vg/SlQhUFjrMiI/AAAAAAAAAV4/-LOB9RMN_UM/s1600-h/9.%20App%5B4%5D.png"><img title="9. App" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="302" alt="9. App" src="http://lh4.ggpht.com/_TEAv5Jw76vg/SlQhVohFahI/AAAAAAAAAV8/43hIwUXR8CQ/9.%20App_thumb%5B2%5D.png?imgmax=800" width="499" border="0" /></a> </p><br /><br /><p>Ahora, a divertirse! </p><br /><br /><p>Saludos!<br /><br /><strong>Zaiden</strong></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-4309538633168858697?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com0tag:blogger.com,1999:blog-3033548414831637355.post-58079799089892723272009-05-24T13:58:00.008-03:002009-05-24T18:11:14.620-03:00Visual Studio 2010 Beta 1: Primeras Impresiones<p>Como ya mencioné en el post anterior, luego de solucionar los problemas severos de performance causados por la combinación WPF + Aceleración de VMWare pude empezar a probar el Beta 1 de Visual Studio 2010.</p><p>Por alguna razón oscura que no llego a comprender, en MS decidieron que sería una buena opción hacer que Visual Studio utilice WPF en la capa de presentación.</p><p>La ventaja de esto es que la posibilidad de tener cientos y cientos de efectos, transiciones, menúes voladores y demas yerbas, mas la posibilidad de hacer sumamente extensible la UI del afamado IDE.</p><p>Pero todo esto viene con un precio... la performance. Si Visual Studio 2008 ya era pesado, la nueva versión salta una o dos categorías mas: iniciar el IDE, abrir una solución chica y compilarla se lleva nada mas y nada menos que 238MB de ram (mas 14MB del PresetantionFontCache).</p><p>Igualmente, estos valores y la performance presentada son indicadores que deben ser tomados con pinzas, ya que al ser el Beta 1, todavía queda un largo camino para dar lugar a optimizaciónes (las cuales espero, por el bien de mis VMs, que aparezcan!).</p><p>Otro problema que encontré (también atribuible al estado de Beta del producto) fue la cantidad de crashes que tuve. Durante el coding del ejemplo que dejé al final (una tarde) me habra crasheado unas 5 veces... bastante mas de lo tolerable. Esperemos que la estabilidad sea un punto importante a mejorar en la proxima Beta o RC</p><br /><p>Cerrado este tema, pasemos a los "chiches" nuevos que trae:</p><p><strong>.NET 4 (beta) y C# 4</strong><br /><br />Nueva version del CLR y del lenguaje estrella de la plataforma .NET. En este otro post (http://zpodblog.blogspot.com/2009/01/material-de-la-conferencia-sobre-c-4.html) pueden bajar una presentación que dimos con RodoF sobre los features nuevos incluidos en el lenguaje (tipado dinámico, parametros opcionales y por nombre, co y contra varianza en parametros de tipos, y algunas cosas mas).</p><p><strong>F#</strong><br /><br />Esta versión de Visual Studio es la primera en incluir este lenguaje funcional para la plataforma .NET.<br />Debo decir que todavía no me puse a ver mucho sobre el mismo, pero será cuestion de encontrar una excusa suficientemente buena como para incluir alguna librería que tenga que hacer en F# para algún proyecto a futuro.<br />Por ahora los dejo con un bonito ejemplo de como obtener el n-esimo termino de la suceción de fibonacci (no puedo evitar caer en los clásicos) en F#:</p><pre>let rec fibonacci elem =<br />match elem with<br />| 1 -> 1<br />| 2 -> 1<br />| n -> fibonacci (n - 1) + fibonacci (n - 2)<br /><br />Printf.printf "Ingrese numero de termino: "<br />let termino = System.Console.ReadLine();<br /><br />Printf.printfn "%i" (fibonacci (System.Int32.Parse termino))<br />let k = System.Console.ReadKey();</pre><p><strong>Parallel Extensions</strong><br /><br />Quienes hayan tenido que hacer optimizaciones en algún proyecto sabrán que uno de los primeros puntos a mirar es la paralelización de tareas independientes. Las Parallel Extensions vienen a simplificar este tipo de tareas.<br />Por ejemplo, en caso de tener una colección y querer aplicar una funcion a cada uno de los elementos, en vez de hacer un viejo y querido "foreach", podemos hacer:</p><pre>miColeccion.AsParallel().ForAll(elem =><br />{<br />//codigo a ejecutar por cada elemento de la colección<br />});</pre><p>La gran ventaja de esto es que nos abstraemos de todo el manejo de concurrencia, manteniendo la ganancia de performance.</p><p><strong>Sequence Diagram</strong><br /><br />Si hacemos click derecho sobre un método, vamos a notar que hay una nueva opción llamada "Generate Sequence Diagram". Al seleccionarla nos pregunta la profundidad máxima para las llamadas del diagrama y si queremos excluir las llamadas a clases dentro de ciertos namespaces (como System, u otros personalizables). Finalmente, nos presenta un diagrama como este:</p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_TEAv5Jw76vg/ShmDqr9MfTI/AAAAAAAAAPw/AR5TiVPLapc/s1600-h/SequenceDiagram.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 278px;" src="http://2.bp.blogspot.com/_TEAv5Jw76vg/ShmDqr9MfTI/AAAAAAAAAPw/AR5TiVPLapc/s320/SequenceDiagram.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5339443602601573682" /></a><br /><p>Este es un feature sumamente útil en caso de tener que comprender lo que hace un código ajeno, sin tener que empezar a navegar todo el código! (y pensar que yo casi me hago una herramienta para generar estos diagramas... por suerte nunca prosperó!)<br /><br />Definitivamente, una gran adición al Visual Studio.</p><p><br /></p><p>Bueno, por ahora esto es lo que pude ver. Me queda pendiente el "Architecture View" y varios features mas que ni siquiera llegué a ver.</p><p>Como extra, dejo mi primer proyectito hecho en C# 4 que permite acceder datos provenientes de una conexión de ADO.NET levantando los campos como propiedades dinámicas del resultado y pudiendo aplicar un pipeline de filtros que hagan transformaciones sobre el resultado al ser obtenido.<br /><br />La idea es poder hacer este tipo de cosas</p><pre>using (var conn = new DynamicConnection(realADOConnection, new ImageMapper()))<br />{<br />dynamic result = conn.Query("SELECT * FROM Customer WHERE IdCustomer = @0", 37);<br />/* O tambien<br />dynamic result = conn.Query("SELECT * FROM Customer WHERE IdCustomer = @IdCustomer",<br />DynamicConnection.CreateParameter("@IdCustomer", 37));<br />*/<br /><br />foreach (dynamic row in result) //recorrer el resultado con un foreach<br />{<br /> //lectura directa<br /> int id = row.IdCustomer;<br /> string name = row.Name;<br /><br /> /*<br /> Aca, el ImageMapper se encarga de leer el campo<br /> y mapearlo a un Image<br /> */</pre><pre> Image customerPicture = row.Picture;<br /> grid.AddRow(id, name, customerPicture);<br />}<br /><br />//Obtengo un solo valor<br />dynamic val = conn.QueryValue("SELECT TOP 1 Name FROM Customer WHERE Id = @0", 37);<br />MessageBox.Show(val);<br />}</pre><p>Lo pueden bajar de aca: <a target="_blank" href="http://www.mediafire.com/download.php?mzjdwtjtjmi">DynamicDataAccess</a></p><p><br />Hasta la próxima!<br /><strong>Z</strong><br /></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-5807979908989272327?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com2tag:blogger.com,1999:blog-3033548414831637355.post-56680387616820453552009-05-24T11:47:00.003-03:002009-05-24T11:53:07.228-03:00Problemas de super-lentitud con la Beta 1 de Visual Studio 2010?<div>Bueno, en caso de estar trabajando con VMWare, posiblemente el problema sea que está activada la aceleración 3D en la VM.</div><div>Aparentemente este supuesto <i>feature</i> de VMWare tiene problemas para correr cosas hechas en WPF y dado que el nuevo <b>Visual Studio 2010</b> lo usa extensivamente, la diferencia de velocidad es mayor a <i>100x</i> una vez desactivada la "aceleración" (o, mejor dicho, <i>desaceleración</i>)</div><div>Ya mejorada la velocidad, con una VM de 2GB es bastante usable, aunque usa unas fuentes sospechosamente borrosas, como todo lo hecho con <b>WPF</b>.</div><div>En breve subo un post con las primeras impresiones del nuevo IDE de Microsoft y el primer proyectito <i>no-charla</i> (o al menos, no usado en una charla <i>todavía</i>) de <b>C# 4</b>.</div><div><br /></div><div>Saludos!</div><div><b>Z</b></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-5668038761682045355?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com0tag:blogger.com,1999:blog-3033548414831637355.post-72860023995893977392009-05-17T20:16:00.005-03:002009-05-17T20:25:06.529-03:00MTGDeck Version 0.5<div style="text-align: left;">Paso a presentarles la primera version Beta (0.5) del MTGDeck!</div><div><br /></div><div>Este programa/juego permite jugar al conocido juego de trading cards "Magic: The Gathering" desde la computadora a través de la red, sin la necesidad de comprar los no-tan-baratos set de cartas, pudiendo probar distintos mazos, combinaciones, estrategias, etc...</div><div><br /></div><div>El juego esta separado en dos aplicaciones distintas:</div><div> </div><div>- <i>Servidor:</i> programa encargado de almacenar la información de las manos de los jugadores y de comunicarlos entre si. El mismo puede servir varias partidas distintas y para jugar siempre será necesario acceso al servidor donde se aloje la partida a la cual se desea ingresar.</div><div> </div><div>- <i>Cliente</i>: programa desde el cual - conectándose a un servidor - permite jugar partidas de Magic contra el resto de los jugadores conectados.</div><div><br /></div><div><br /></div><div><b>Que NO hace el programa</b>:</div><div><br /></div><div> - NO valida las (complicadas) reglas del juego y cada una de sus cartas. El propósito de este programa es el de reemplazar el set de cartas, y nada mas. El hecho de "jugar" propiamente dicho todavía queda a cargo de los humanos.</div><div><br /></div><div> - NO permite jugar contra la computadora. El único modo de jugar solo es, simplemente, no tener contrincante.</div><div><br /></div><div> - NO te va a ayudar a ganar minas (aceptémoslo, es un juego bien nerd)</div><div><br /></div><div><br /></div><div><b>Que SI hace el programa</b>:</div><div><br /></div><div> - Permite jugar desde uno (practica solo) hasta varios jugadores dentro de la misma partida</div><div><br /></div><div> - Permite armar mazos, utilizar cualquier carta que haya existido para Magic: The Gathering, referenciándolas por su nombre en ingles</div><div> - ¡Te ahorra dinero! (¡no hoy que ir a comprar cartas!)</div><div> - ¡Te proporciona horas y horas de diversión nerd!</div><div><br /></div><div><b>Requerimientos</b>:</div><div> - Windows XP o superior con todos sus Service Packs.</div><div> - .NET Framework 3.5 con todos sus Service Packs.</div><div> - Algun tipo de conexión de red (y al menos la primera vez que se usa cada mazo, conexión a internet).</div><div><br /></div><div><b>Info sobre el proyecto: </b></div><div> - UI hecha con .NET 3.5 en Winforms.</div><div> - Para la comunicación entre los clientes y el server se puede utilizar tanto un cliente/server de WCF funcionando con basicHttpBinding - proximamente esto será configurable - y otro cliente/server hecho con old-school Remoting. </div><div>Esto tiene dos motivos: por un lado, hay algunas computadoras en los cuales el server de WCF no funciona. Todavía no pude encontrar el problema, pero voy a seguir buscando. El otro motivo es que las librerías de Remoting en Mono estas mucho mas maduras que las de WCF y, pese a que todavía me topo con algunos errores del lado de Mono, pienso que dentro de poco voy a poder tener la app mas cross-platform (si me vuelvo suficientemente loco me pongo a hacer una interfaz nativa para Mac y todo!).</div><div>Por default, se utiliza el Client de WCF, pero esto se puede modificar por configuración (y ya que es levantado por reflection... ¡Pueden hacer sus propios clientes y servers en casa!)</div><div><br /></div><div><b>FAQ</b>:</div><div><br /></div><div>- ¿De dónde bajo el juego?</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Esta versión la pueden bajar de <a href="http://mtgdeck.googlecode.com/files/MTG-0.5.rar">aca</a>. El código fuente y las futuras versiones las podrán encontrar en el sitio de <a href="http://code.google.com/p/mtgdeck">MTGDeck en Google Code</a><br /></div><div><br /></div><div> - ¿Cómo empiezo?</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>El paquete incluye un pequeño manual de usuario. Ahí esta toda la info necesaria para salir andando.</div><div><br /></div><div> - Todo muy lindo pero... ¡Cómo armo mi mazo?</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>El formato del archivo de mazos es muy simple: cada línea tiene la cantidad de cartas de un tipo, seguida por el nombre de la carta. Las lineas que comienzan con "#" son ignoradas. Junto con el paquete se incluye un ejemplo.</div><div><br /></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Para armar mazos, recomiendo la siguiente página: http://www.essentialmagic.com/decks/</div><div><br /></div><div> - ¡No puedo conectarme al servidor! ¿Qué pasa?</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Posiblemente, el problema sea que el firewall de Windows (o algún otro) no este permitiendo conectarse al puerto 1234 (o el que esté configurado) en la computadora donde el servidor esté ejecutando. Para solucionarlo, habilitar el puerto en el firewall o desactivarlo por completo. </div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Durante las pruebas me ha ocurrido que hay máquinas donde el server indica que levantó correctamente, sin embargo es imposible conectarse, incluso desde la máquina local. Cuando tenga identificado este error y lo solucione, avisaré.</div><div><br /></div><div> - Encontré un error. ¿Cómo lo reporto?</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Pueden contactarse conmigo por twitter (<a href="http://twitter.com/pablozaiden">http://twitter.com/pablozaiden</a>), por mail o dejando un comentario en el blog.</div><div><br /></div><div> - Me gustaría que el juego tuviese tal o cual feature. ¿Qué puedo hacer?</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Nuevamente, podes contactarme por alguno de los medios nombrados anteriormente y si sos desarrollador podes contribuir con el desarrollo (proximamente)</div><div><br /></div><div><br /></div><div>A continuación dejo unos screenshots del juego en acción:</div><div><br /></div><div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_TEAv5Jw76vg/ShCb_k3d_4I/AAAAAAAAAPo/fXWU1akK1ts/s1600-h/Picture14.png"><img src="http://2.bp.blogspot.com/_TEAv5Jw76vg/ShCb_k3d_4I/AAAAAAAAAPo/fXWU1akK1ts/s320/Picture14.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5336937074964430722" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 191px; " /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_TEAv5Jw76vg/ShCbz5LNu7I/AAAAAAAAAPg/jXN3axRSKV8/s1600-h/Picture8.png"><img src="http://3.bp.blogspot.com/_TEAv5Jw76vg/ShCbz5LNu7I/AAAAAAAAAPg/jXN3axRSKV8/s320/Picture8.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5336936874257529778" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 230px; " /></a></div><div><br /></div><div>Saludos!</div><div><b>Z</b></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-7286002399589397739?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com0tag:blogger.com,1999:blog-3033548414831637355.post-43850278686480802872009-05-13T09:06:00.004-03:002009-05-13T09:10:17.831-03:00Pirata InformáticoHasta donde yo sabía, un pirata es <i>una persona con pata de palo, un loro en el hombro, sed por los doblones y - eventualmente - con la habilidad de ganarle un duelo de insultos al Sword Master</i>.<div><br /></div><div>Por lo tanto, la pregunta que viene al caso es: por que los medios de comunicación se empeñan en llamar <i>pirata</i> a la gente que encuentra vulnerabilidades en sistemas de software o - mas bizarro aún - comparte música por internet?</div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-4385027868648080287?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com4tag:blogger.com,1999:blog-3033548414831637355.post-45224822553117932232009-05-12T23:10:00.005-03:002009-05-12T23:17:23.886-03:00Primera reunion de ALT.NET Argentina<p>Tratando de mantener la vida del blog y siguiendo lo comentado en la lista de mails ALT.NET Argentina, vamos a hablar un poco de lo que fue la primera reunión del grupo</p> <p>(para quien no sepa de que trata esto, puede darse una vuelta por: <a href="http://altdotnet.org/">http://altdotnet.org/</a> y/o <a href="http://altnet-argentina.pbworks.com/">http://altnet-argentina.pbworks.com/</a> )</p> <p>Pese a la no-tan-feliz combinación de día/horario para el inicio de esta reunión (sábado a las 9 de la mañana!) el ambiente era muy bueno: muchas caras conocidas - bastante mas dormidas que de costumbre - y muchas ganas por empezar las sesiones pensadas para el día.</p> <p>A eso de las 10.00, nos fuimos presentando en ronda (no pude evitar tirar un chiste) y pasamos a contar que temas habían propuestos para las sesiones del día y arreglar entre todos los horarios y las salas de cada uno.</p> <p>Independientemente del tema a tratar en cada una, se utilizó la modalidad de "open space", donde cada uno es libre de opinar y plantear su punto de vista cuando le parezca - siempre y cuando se haga de forma ordenada - y no las clásicas charlas con un orador y muchos escuchas.</p> <p>Durante el día hubieron 4 franjas donde se llevaron a cabo sesiones simultáneas. En particular, voy a hacer una pequeña reseña sobre las cuatro donde yo participé:</p> <p>(no recuerdo los nombres concretos, pero con el título de fantasía que puse se entiende)</p> <p><b></b><br /></p> <p><b>1. SOA: ¿Vivo o muerto? ¿Cáncer o salvación?</b></p> <p>En esta charla hubieron 4 a 6 sillas adelante, dándole al usuario de las mismas el derecho a hablar, siguiendo estas reglas:</p> <p>- Siempre debe haber una silla vacía</p> <p>- Si alguien quiere hablar, debe sentarse en una de esas sillas</p> <p>- Si quedan todas las sillas ocupadas, deberá retirarse quien esté hace mas tiempo (o quien considere que ya no está aportando a la conversación, pero esto queda a criterio de cada uno)</p> <p>La misma empezó comentando la experiencia de distintas personas que llevaron (o intentaron llevar a cabo) proyectos con arquitecturas que implementaban el patrón SOA y a raíz de esto, muchos - me incluyo - comentamos donde nos parecía que estaban las falencias usuales en este tipo de emprendimientos, cuales eran los beneficios, que costos se pagaban por intentar hacer SOA "porque es la palabra de moda" y cuando valía la pena realmente tener componentes de un proyecto que siguieran este patrón.</p> <p><b></b><br /></p> <p><b>2. Microsoft... ¿Está innovando?</b></p> <p>Este es un tema que propuso Miguel Angel Saez y, pese a que no mucha gente se prendió, me pareció un tópico sumamente interesante para tratar.</p> <p>Acá charlamos sobre las alternativas a distintos problemas, viendo la forma - o formas - en que lo encaran Microsoft, otras empresas como Sun, Oracle, Amazon, Google, etc. y por último "la comunidad open source".</p> <p>Para cada uno hablamos sobre cuanto de "inspiración" y cuanto de creatividad hubo en su creación y hacia donde veíamos el rumbo de evolución de cada una de estas tecnologías o productos.</p> <p><br /></p> <p>Hacia el final de la sesión estuvimos hablando sobre Windows 7, su comparación con OS X (o inspiración en...) y cual grande - o pequeño - era el salto desde Windows Vista.</p><p><br /></p> <p><b>-- Pizza Break --</b></p> <p>El almuerzo fue una gran sesión en si misma: todos hablando con todos sobre lo discutido en las sesiones anteriores, tratando de ver que nos perdimos y contando - mordisco de muzzarella de por medio - lo que aprendimos de los demás en las charlas que estuvimos.</p> <p><br /></p><p>Y sigue la tarde con...</p> <p><b>3. YARF: Yet-Another-Rodo-Framework, o ¿Cuándo debo meter qué cosa?</b></p> <p>Esta vez, pese a ser unos cuantos usamos la vieja y querida ronda para hablarnos entre todos y no tuvimos ningún problema.</p> <p>Acá se charlo sobre para que tipos de desarrollo pensábamos que era mejor utilizar tal o cual framework o tecnología, o si - como algunos preferimos - hacernos el nuestro propio framework a media.</p> <p>Hablamos de ventajas y desventajas de pensar necesidades a futuro, cuándo conviene reutilizar y cuándo conviene tirar lo que tenía y volver a pensar desde cero una mejor solución. Tocamos temas como la sobreingeniería de las soluciones planteadas, problemas con la división en capas (ya sea por defecto o por exceso) y varias cosas mas.</p><p><br /></p> <p><b>4. .NET hace monerías</b></p> <p>La idea de esta charla fue hablar sobre las experiencias que hayamos tenido utilizando Mono (implementación Open Source de .NET) en distintas plataformas y poder contarles a los que nunca habían escuchado de este proyecto, o no lo habían probado, cual era el estado del mismo y que se podía o no hacer en comparación a .NET.</p> <p>Durante la charla se mostró un poco de Mono en acción desde una maquina con Linux y mi Mac. Mostramos el REPL de csharp que viene incluido con Mono, explotando el hecho de que el compilador es provisto como "una librería mas". También vimos el plugin de Moonlight - implementación de Mono de Silverlight - corriendo dentro de Firefox en Linux y un pequeño vistazo a la IDE multiplataforma Monodevelop.</p> <p><br /></p> <p>Bueno, con esto cierro el post de hoy. Si alguien quiere, pregunte sobre algún tema mas en particular de las sesiones y, de acordarme, con gusto responderé.</p> <p>Saludos y hasta la próxima (donde pienso que subiré la primer versión beta del MTGDeck)!</p> <p><b>Z</b> </p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-4522482255311793223?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com2tag:blogger.com,1999:blog-3033548414831637355.post-4007568923431718552009-05-10T09:53:00.003-03:002009-05-10T10:15:09.140-03:00Usando el MTGDeck para intentar devolverle la vida al blogHace unos 6 meses empecé otro de tantos proyectos que suelo dejar sin terminar... sin embargo el mismo tuvo su breve mención dentro del blog: <span style="font-weight:bold;">MTGDeck</span><br /><br />La idea de este proyectito era poder jugar al juego de trading cards Magic: The Gathering, sin la necesidad de tener las cartas (probar mazos, combinaciones, etc...).<br />Como implementar las 192381092381290 reglas que hay para cada carta de Magic era algo impensable, se me ocurró que la funcionalidad del juego sería <span style="font-style:italic;">únicamente</span> la de suplantar las cartas (y mesa) del juego. Con esto quiero decir que el seguimiento de las vidas, cumplimiento de reglas, fases del juego, etc... seguirían a cargo de los jugadores.<br /><br />Para permitir jugadas de mas de 2 jugadores, encaré el desarrollo de esta aplicación directamente como <span style="font-style:italic;">client-server</span>, donde el server guardaría el estado de las manos y cartas jugadas de cada uno de los jugadores y el cliente simplemente le enviaría cuales son los cambios hecho en la mano propia.<br /><br />Para desarrollarlo decidí - y no por casualidad - empezar por el server (ya que carece de ese cáncer que mucho conocemos como <span style="font-style:italic;">la interfaz gráfica</span>).<br /><br />No mucho tiempo después ya tenía listo el servidor... y ahí es cuando las cosas se pusieron feas: al empezar a desarrollar el cliente pude hacer un repositorio de cartas que se encargaba de traer la imagen de cada carta, un prototipo de lo que sería la mano de cada jugador... y perdí el interés.<br /><br />Siempre lo mismo... en el momento que hay que hacer la UI mis proyectos caen a velocidades estrepitosas.<br /><br />Sin embargo, hace unas semanas decidí que era hora de terminar lo que alguna vez empecé y pese a su <span style="font-style:italic;">no-del-todo-hermosa</span> interfaz gráfica, el juego parece estar andando.<br /><br />Actualmente, el proyecto está en las últimas fases del <span style="font-style:italic;">alpha</span>-testing (<span style="font-style:italic;">gracias Krako!</span>) y será liberado en breve a las masas!<br /><br />Para que se vayan dando una idea, toda la comunicación esta manejada con WCF (actualmente usando BasicHttp), pero por las dudas también hice un conector basado en remoting, hecho <span style="font-style:italic;">a la old school</span>.<br /><br />La interfaz de usuario está hecha en Winforms, pero la idea es que, eventualmente, pueda ser portada a otras cosas (GTK#, WPF, Web... iPhone?) ya que los servicios que expone el server pueden ser consumidos desde todos los anteriormente nombrados.<br /><br />Bueno, con esto cierro. Supongo que durante esta semana estaré poniendo la primer beta y veremos si tiene tanto éxito en <span style="font-style:italic;">Taringa</span> como lo tuvo mi RapidshareDownloader (nota al pie: si alguien lo sigue usando, le recomiendo pasar a JDownloader que es mucho mas potente)<br /><br />Saludos!<br />Z<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-400756892343171855?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com0tag:blogger.com,1999:blog-3033548414831637355.post-64525169676108356902009-01-21T10:31:00.007-02:002009-01-21T10:50:20.719-02:00Material de la conferencia sobre C# 4Ya está disponible para bajar el material que usamos ayer con <a target="_blank" href="http://weblogs.shockbyte.com.ar/rodolfof/">RodoF </a> en la conferencia "Agregando dinamismo al código: C# 4 entra en escena" sobre las nuevas características que van a venir con C# 4 y la próxima versión del .NET Framework.<br /><br /><a target="_blank" href="http://www.mediafire.com/download.php?nu3qjjryzin">Link</a><br /><br /><img style="display:block; margin:0px auto 10px; text-align:center;width: 500px; height: 373px;" src="http://farm4.static.flickr.com/3479/3215457232_c38de397a5.jpg" border="0" alt="" /><br /><br />Hasta la próxima!<br />Z<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-6452516967610835690?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com0tag:blogger.com,1999:blog-3033548414831637355.post-89031247838117166402008-11-15T16:04:00.001-02:002008-11-15T16:04:05.651-02:00Chiche nuevo: iPod touch (2da gen)Después de haber probado el ipod de johnny, me vinieron muchas ganas de cambiar mi viejo mp3 player por algo mas novedoso y... Taraaaaa! Ipod touch de 16 gb nomás!!<br /><br />El bicho esta muy bueno. Yo pensaba que escribir con el tecladito iba a ser molesto, pero el autocorrector que tiene es tan bueno que escribir este post desde el ipod es casi mas fácil ue desde la mac!<br /><br />Lo único de malo que tiene esta version es que (todavía) no se puede hacer el jailbreak, por lo que estoy limitado a las apps disponibles en el app store de apple, que no son pocas, pero bueno... Yo quería usar mono acá!<br /><br />Hasta el prox post!<br /><br />Z<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-8903124783811716640?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com3tag:blogger.com,1999:blog-3033548414831637355.post-16059733808973926232008-10-06T12:12:00.003-03:002008-10-06T12:29:07.804-03:00Charla de Voice Recognition y Synthesis con .NET 3.xEste sabado dimos con RodoF una charla en el CodeCamp sobre Voice Recognition y Synthesis utilizando .NET 3.x.<br />La presentación la pueden bajar de <a href="http://www.mediafire.com/?u0nu4immjye">aca</a>.<br /><br />Durante la charla, estuvimos mostrando el proyecto de KeySimulator - VoiceCommander, el cual ya estuve comentando en el blog. Pueden obtener el código desde <a href="http://www.codeplex.com/KeySimVoiceCommander/">Codeplex</a>.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_TEAv5Jw76vg/SOouiE_EiPI/AAAAAAAAAAM/IUdA2ez0h4E/s1600-h/CodeCamp2008VoiceRecognition2.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_TEAv5Jw76vg/SOouiE_EiPI/AAAAAAAAAAM/IUdA2ez0h4E/s320/CodeCamp2008VoiceRecognition2.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5254063078269815026" /></a><br /><br />Saludos!<br /><br /><strong>Z</strong><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-1605973380897392623?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com2tag:blogger.com,1999:blog-3033548414831637355.post-41216185058589973232008-09-26T11:02:00.003-03:002008-09-26T11:06:18.241-03:00Aplicacion recomendada: Facebook Exporter for iPhotoAyer me topé con una gran aplicacion que permite exportar directamente nuestros albumes de iPhoto a una cuenta de Facebook. La pueden bajar desde aca: <a href="http://developers.facebook.com/iphoto/">Facebook Exporter for iPhoto</a>.<br /><br />Dentro de unos dias voy a tratar de ponerme a ver que APIs expone facebook para ver que nueva aplicacion puedo agregar a la gran seccion de "Cool and Useless"<br /><br />Saludos!!<br /><br /><strong>Z</strong><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-4121618505858997323?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com0tag:blogger.com,1999:blog-3033548414831637355.post-8498616444518211682008-09-24T11:07:00.002-03:002008-09-24T11:13:26.865-03:00Error spawning rc.exe - C++ - Visual Studio 2008Como continuación del post anterior, comento como solucionar el error que me llevó a reinstalar el Visual Studio 2008.<br /><br />Al intentar compilar proyectos de C++, tiraba el error:<br /><blockquote>Error spawning rc.exe</blockquote><br /><br />Aparentemente, el problema es que este se instala al elegir el paquete de c++ tools (o algo asi) dentro de la instalación de Visual Studio. Por lo tanto, de no instalarlo no van a poder compilar nada.<br /><br />Saludos!<br />Z<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-849861644451821168?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com1tag:blogger.com,1999:blog-3033548414831637355.post-20197510646831788612008-09-24T10:32:00.004-03:002008-09-24T11:02:10.491-03:00Problemas desinstalando Visual Studio 2008Debido a que mi Visual Studio 2008 decidió - sin mi consentimiento - que no iba a poder compilar proyectos de C++, decidí desinstalarlo y reinstalarlo para ver si algo se arreglaba.<br />El problema (va, <em>otro</em> de los problemas) fue que al intentar hacerlo, apareció el siguiente error:<br /><br /><blockquote>A problem has been encountered while loading the setup components. Canceling Setup.</blockquote><br /><br />Despues de mucho (realmente <em>mucho</em>) dar vueltas por internet buscando una solución, encontré que el problema era que el hotfix KB952241 (bajado por Windows Update) trajo un bug en el instalador, resultando en el error encontrado.<br />Habiendolo desinstalado, todo volvió a la normalidad.<br /><br />Si a alguien mas le pasa, espero que por leer esto no tenga que pasar tanto tiempo buscando soluciones como yo.<br /><br />Un saludo!<br />Z<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-2019751064683178861?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com3tag:blogger.com,1999:blog-3033548414831637355.post-21167739577982125842008-09-22T09:56:00.004-03:002008-09-22T10:26:56.439-03:00Rapidshare Downloader y CodeCampHola nuevamente!<br /><br />Después de algunos meses volví para postear aca.<br />Para (re)comenzar, voy a dejar una aplicación que hice hace unos meses la cual, dada una lista de links de Rapidshare, los baja automaticamente.<br /><br />Debo decir que no es el código mas bonito del mundo, pero cumple con su funcion mas que bien.<br /><br />Originalmente, la aplicación funcionaba tanto en Windows como en Linux y OS X con Mono, pero aparentemente desde la beta 1 de Mono 2.0 se rompió algo relacionado con los web requests y no estan saliendo bien los requests hechos por POST, necesarios para esta aplicación, asi que por ahora solo funcionará en Windows (tal vez en Linux tambien, aunque lo dudo mucho).<br /><br /><a href="http://www.mediafire.com/?megmt2llgyg">Programa y Fuentes</a><br /><br />Próximamente voy a estar publicando una aplicación que estamos armando con Giga para jugar al Magic PC a PC usando remoting o WCF para conectarse.<br /><br />Por otro lado, quiero avisar que el día 4 de Octubre desde las 10.00 hasta las 19.00 se realizará el evento <a href="http://www.microsoft.com/Argentina/CodeCamp/">Microsoft CodeCamp</a>, en el cual estaré dando una conferencia con <a href="http://weblogs.shockbyte.com.ar/">RodoF</a> sobre el uso del motor de Voice Recognition y Voice Synthesis desde .NET 3.x. No se lo pierdan!<br /><br />Saludos!!<br /><br />Z<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-2116773957798212584?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com0tag:blogger.com,1999:blog-3033548414831637355.post-85541491976773097742008-06-10T09:53:00.002-03:002008-06-10T10:01:45.433-03:00zPod Reloaded: Vuelta al blog, desde el otro lado de La Fuerza!Si... ya se. No posteo nada desde hace 2 meses.<br />La verdad es que intenté postear algo, pero no se me ocurrió nada piola...<br /><br />Ahora estoy <span class="Apple-style-span" style="font-style: italic;">oficialmente</span> del lado de la luz: tengo una MacBook :) Por lo que mis problemas configurando y tuneando drivers locos hechos por gente loca de internet se acabaron (por lo menos por un tiempo... mi viejo quiere probar ponerse OS X en su notebook!)<div><br /></div><div>Actualmente estoy laburando en un proyecto que exprime a fondo los features nuevos de C# 3, asi que si hacemos algo realmente copado, veré de postearlo. <span style="font-style:italic;"></span></div><div><br /></div><div>Ya que no postié nada que valga la pena, les dejo dos videos que muestran <span class="Apple-style-span" style="font-style: italic;">cuan duro</span> es trabajar en Lagash :)</div><div><br /><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/K1p-BwxK1vU&hl=en"></param><embed src="http://www.youtube.com/v/K1p-BwxK1vU&hl=en" type="application/x-shockwave-flash" width="425" height="344"></embed></object><br /><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/AG-z-0uJDhc&hl=en"></param><embed src="http://www.youtube.com/v/AG-z-0uJDhc&hl=en" type="application/x-shockwave-flash" width="425" height="344"></embed></object><br /></div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Z</span></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-8554149197677309774?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com0tag:blogger.com,1999:blog-3033548414831637355.post-4635909765002221792008-04-06T17:34:00.003-03:002008-04-06T17:40:07.150-03:00Monitor dual en OS XDespues de varios meses de estar usando OS X, pude configurarlo para usar la salida VGA como segundo monitor. Para hacerlo hay que tener instalado el Leopard Graphics Update, usar <a href="http://www.mediafire.com/?02ykgjthljz">estas</a> extensiones y arrancar la maquina con el monitor enchufado.<br /><br />Z<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-463590976500222179?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com1tag:blogger.com,1999:blog-3033548414831637355.post-47451466052500576262008-03-24T22:01:00.003-03:002008-03-24T22:10:23.407-03:00Frase célebreHace mucho que no posteo nada, asi que voy a usar una frase célebre de relleno:<br /><br /><blockquote>Computer science education cannot make anybody an expert programmer any more than studying brushes and pigment can make somebody an expert painter</blockquote><br /><a href="http://en.wikipedia.org/wiki/Eric_S._Raymond">Eric Raymond</a><br /><br /><strong>Z</strong><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-4745146605250057626?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com2tag:blogger.com,1999:blog-3033548414831637355.post-54160309939918096482008-03-03T11:17:00.005-02:002008-03-03T12:30:18.538-02:00El eslabón que faltaba entre el .NET Framework y los browsers: VoltaHace un mes, mas o menos, mi amigo <a href="http://blogs.southworks.net/johnny">Johnny</a> me había comentado al pasar sobre un <span style="font-style: italic;">compilador de MSIL a Javascript</span> que estaban haciendo en Microsoft, pero no le di mucha importancia. Pensé que era uno de esos proyectos locos que solo servían como prueba de concepto o similar... hasta que lo vi.<br /><br /><a href="http://labs.live.com/volta">Microsoft Volta</a> es un proyecto (todavía en estado alpha o, a lo sumo, pre-beta) de Microsoft Live Labs para poder desarrollar aplicaciones web multicapa sin tener que preocuparse por aprender nuevos lenguajes, lidiar con problemas para hacer javascript cross-browser y varias otras cosas.<br />En cierta manera se puede ver como la respuesta de Microsoft al <a href="http://code.google.com/webtoolkit">Google Web Toolkit</a>, aunque todavía bastante menos maduro y obviamente, usando .NET en vez de Java.<br /><br />Un ejemplo de lo que nos permite hacer Volta es hacer el diseño en HTML de una página, codificar todo su comportamiento desde cualquier lenguaje que trabaje con el .NET Framework y finalmente, el compilador de Volta generará todo el código y las assemblies necesarias para correr todo lo que se quiera correr desde el cliente, y las clases que deban ser ejecutadas desde el servidor serán llamadas de forma transparente, sin tener que agregar nada aparte de un atributo en la clase, indicándolo.<br /><br /><span style="font-style: italic;">Nota antes de intentar usar esto: para poder crear nuevos proyectos de Volta, es necesario tener instalado Visual Studio 2008 y el Tecnology Preview de Volta. Tener en cuenta que es una de las primeras versiones que salen fuera de Microsoft como preview y aún contiene varios bugs y limitaciones.</span><br /><br /><span style="font-style: italic;">Nota sin mucho sentido: como todavía no hay version del Copy Source as HTML para Visual Studio 2008, los ejemplos que voy a mostrar los voy a pegar como imágenes. Perdón por eso, pero hacer que se vea bien el codigo posteado en blogger es una tarea bastante ardua y no tengo muchas ganas de perder tiempo en esto :D</span><br /><br />A continuación les muestro una aplicación de ejmplo que hice, la cual consiste en un simple Chat:<br /><br />Mi idea era la siguiente: hacer una página que tenga 2 textboxes, uno para el nick y otro para el mensaje a escribir, un boton para enviar el mensaje y un div donde se vaya escribiendo el texto del chat.<br /><br />Para empezar, creé el html de la página:<br /><a href="http://www.flickr.com/photos/82637861@N00/2306996193/" title="1 by PabloZaiden, on Flickr"><img src="http://farm3.static.flickr.com/2383/2306996193_e33fe677cf.jpg" width="500" height="323" alt="1" /></a><br /><br />Una vez hecho esto, codifiqué la clase que representa esta página y obtuve los controles desde código manejado para poder usarlos:<br /><a href="http://www.flickr.com/photos/82637861@N00/2306996207/" title="2 by PabloZaiden, on Flickr"><img src="http://farm3.static.flickr.com/2078/2306996207_179b374852.jpg" width="499" height="401" alt="2" /></a><br /><br />En el evento <span style="font-style: italic;">Click</span> del boton de la página hice que se llame al método <span style="font-style: italic;">_btnSend_Click,</span> el cual se encarga de llamar al metodo <span style="font-style: italic;">AddMessage</span> de la clase <span style="font-style: italic;">ChatState,</span> la cual es la encargada de mantener el estado del chat, y luego agrega el nuevo texto al div donde se muestra la conversación:<br /><a href="http://www.flickr.com/photos/82637861@N00/2306996215/" title="3 by PabloZaiden, on Flickr"><img src="http://farm3.static.flickr.com/2258/2306996215_61c62d9aaf.jpg" width="500" height="289" alt="3" /></a><br /><br />Para poder mostrar también lo que el resto de la gente escribía en el chat, necesitaba poder pedirle al servidor que me actualice el contenido del div, por lo que creé un Time que se de dispare cada 5 segudos y llame al metodo UpdateChatBox, el cual se encarga de pedir las nuevas lineas agregadas al chat usando el método <span style="font-style: italic;">GetResponse</span> de la clase <span style="font-style: italic;">ChatState</span> y mostrarlas:<br /><a href="http://www.flickr.com/photos/82637861@N00/2306996219/" title="4 by PabloZaiden, on Flickr"><img src="http://farm3.static.flickr.com/2348/2306996219_c5c9c93ffb.jpg" width="500" height="481" alt="4" /></a><br /><br />Como se habrán dado cuenta, la gran mayoría de todo este código debería correr en el cliente, excepto tal vez por la clase ChatState, la cual debería ejecutar en el servidor, conservando el estado de la conversación. Para hacer esto lo único que hay que hacer es ir a la clase ChatState, hacer click derecho sobre el nombre, ir a <span style="font-style: italic;">Refactor</span> y hacer click en <span style="font-style: italic;">Tire-split to run at origin</span>. Haciendo esto, se le agregará el atributo <span style="font-style: italic;">RunAtOrigin</span>, lo que le indica a Volta que ese código debe ser ejecutado en el servidor y no en el cliente:<br /><a href="http://www.flickr.com/photos/82637861@N00/2306996221/" title="5 by PabloZaiden, on Flickr"><img src="http://farm4.static.flickr.com/3053/2306996221_2fd50b7b32.jpg" width="500" height="324" alt="5" /></a><br /><br />Finalmente, tocando F5 se dispara el browser elegido para debug (se puede usar IE o Firefox) y... listo! Estamos debuggeando nuestra aplicación volta!<br /><br />Aca muestro un ejemplo de la aplicación funcionando:<br /><a href="http://www.flickr.com/photos/82637861@N00/2306996225/" title="6 by PabloZaiden, on Flickr"><img src="http://farm4.static.flickr.com/3158/2306996225_61675b091a.jpg" width="500" height="347" alt="6" /></a><br /><br />Código del ejemplo: <a href="http://www.mediafire.com/?hdxm2xxxd5g">aca</a>.<br />Hasta aca llega el post de hoy. Cuando haga algo mas veo de postearlo.<br /><br /><span style="font-weight: bold;">Z</span><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-5416030993991809648?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com3tag:blogger.com,1999:blog-3033548414831637355.post-41154568048608812532008-02-24T21:39:00.003-02:002008-02-24T21:54:41.618-02:00Me tomo en whisky y empiezo a nombrar especies?La idea nombrada en el título de este post es lo único que me viene a la mente sobre el momento en que los científicos nombraron "Caballito de mar" al caballito de mar.<br /><br />Se me ocurren dos posibles conversaciones:<br /><blockquote><strong>Cientifico A</strong>: <em>... estás loco. Nadie va a ser tan boludo. Esta bien que la mayoría de la gente es bastante ignorante. Pero supongo que de esta <strong>si</strong> se darán cuenta.</em><br /><br /><strong>Científico B</strong>: <em>Vos haceme caso. La gente del populacho son un grupo de ovejas decerebradas. Vos decile que este bicho inerte es un caballo y lo van a comprar como billete del gordo de navidad...</em></blockquote><br /><br />O bien, la otra posibilidad:<br /><blockquote><em>Luego de haberse tomado 2 ginebras, 5 fernet y 4 whiskys...</em><br /><br /><strong>Cientifico A</strong>: <em>Che, encontré un animal de 15cm de largo, con caparazón ocificado, cabeza tupular, carente de dientes y ninguna extremidad...</em><br /><br /><strong>Cientifico B</strong>: <em>Un caballo!</em></blockquote><br /><br />Basado en una reflexión original de <em>Luis Piedrahita</em><br /><br />Hasta la próxima!<br /><strong>Z</strong><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-4115456804860881253?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com1tag:blogger.com,1999:blog-3033548414831637355.post-38351072693452024962008-02-21T12:19:00.002-02:002008-02-21T12:29:24.281-02:00Somos el único animal suficientemente idiota...Se dice que la estupidez humana no tiene límites, ya que somos el único animal suficientemente idiota para <em>tropezar 2 veces con la misma piedra.</em> Básicamente, intentar dos veces lo mismo y esperar distinto resultado<br /><br />Ayer confirme mi humana estupidez.<br /><br />Hace ya unos meses había tratado de utilizar la salida VGA de la notebook desde OS X sin mucho éxito. En el camino, casi destruyo la instalacion de mi máquina ya que me quedó lockeada una resolucion fea y no se veía nada en la máquina. Finalmente pude zafarla y volver a hacerlo andar.<br /><br />Ayer volví a hacer lo mismo esperando tener éxito esta vez (iluso...). Obviamente, volví a destruir la configuración de la resolución de la maquina. El problema es que esta vez de tantas cosas que toque, dejé al sistema imposible de bootear. Por suerte pude levantar la particion desde el DVD de instalacion de OS X, guardar todos los datos importantes en un Pendrive y finalmente... reinstalar :(<br /><br />Conclusión: me terminé durmiendo a las 3.30 de la mañana mientras reinstalaba todo.... por boludo.<br /><br />Hasta la próxima!<br /><br />Z<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-3835107269345202496?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com1tag:blogger.com,1999:blog-3033548414831637355.post-11629807666084823192008-02-07T21:59:00.000-02:002008-02-07T22:04:29.464-02:00Un pequeño paso para el hombre, un gran salto para el desarrollo .NET en OS X: La nueva version de Mono incluye el MonoDevelop para Mac!Gente, desde hace unos dias, el paquete de instalación de Mono para OS X incluye una pequeña sorpresa: MonoDevelop!<div><br /></div><div>Finalmente los usuarios de OS X tenemos un entorno de desarrollo decente, con completado de codigo y toda la bola para .NET!</div><div><br /></div><div>Screenshot:</div><div><a href="http://www.flickr.com/photos/82637861@N00/2249693898/" title="MonoDevelop en OS X by PabloZaiden, on Flickr"><img src="http://farm3.static.flickr.com/2163/2249693898_32bb4408fe.jpg" width="500" height="313" alt="MonoDevelop en OS X" /></a><br /></div><div><br /></div><div>Hasta la próxima!</div><div><span class="Apple-style-span" style="font-weight: bold;">Z</span></div><div><br /></div><div>PD: pese a que ya no va a ser necesario, voy a ver si le programo una interfaz en GTK# o similar al ZSense para poder correrlo en OS X sin depender de Windows.Forms</div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-1162980766608482319?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com0tag:blogger.com,1999:blog-3033548414831637355.post-22149950083318645602008-01-20T23:08:00.001-02:002008-01-21T00:08:32.239-02:00Intellisense de bolsillo (y multiplataforma): ZSense!Dado que la gran mayoría de mis amigos están disfrutando de sus vacaciones, ya sea en la costa, el sur o en el exterior, este fin de semana fue bastante aburrido: me quedé en casa practicamente sin hacer nada. Todo parecía seguir asi hasta que me vino una idea a la cabeza...<br /><br />Desde que instalé OS X en la laptop estoy queriendo desarrollar aplicaciones .NET usando el port de Mono que hay para OS X. El gran problema que tengo es que al no haber port de MonoDevelop (o al menos, no hay sin tener que recompilar medio universo y bajar nosecuantas librerías extra...) termino levantando una VM con Windows XP y el Visual Studio. No pido tener un IDE que se integre con el debugger ni mucho menos, sino que pido algun editor que tenga IntelliSense para no tener que estar programando con la ayuda abierta constantemente.<br /><br />Aqui es donde aparece la idea que me vino el día de hoy: lo que hay que hacer es tener el IntelliSense dentro de una aplicacion hecha en .Net, asi, cuando quiera desarrollar, la puedo usar como referencia.<br /><br />Sin mas presentación, les entrego a... <span style="font-weight: bold;">ZSense!</span><br /><br />Este es un proyectito bastante chico que hice hoy (pero planeo seguir mejorando con el tiempo) que recibe una linea de código con tipos de .Net y va mostrando en una lista las opciones disponibles para seguir escribiendo la linea.<br /><br />Esta primera versión tiene algunos <span style="font-style: italic;">detalles ásperos</span>: el tipo inicial debe estar escrito entre comillas dobles. Por ej, una linea válida sería: <span style="font-style: italic;">"System.Int32".GetHashCode().CompareTo(System.Int32)</span><div>Como pueden ver, la manera de indicar que sobrecarga de un método se quiere usar es escribiendo el tipo de dato de cada parámetro, separados por comas.<br /></div><div><br /></div><div>Si se quieren usar mas assemblies aparte de las predeterminadas, se pueden cargar en la lista de la izquierda.</div><div><br /></div><div>Para mas detalle, vean el código! (si, ya se... hay unas cuantas cosas que podrían estar mejor - como el parsing - pero lo quería sacar andando rápido. Ya tendré tiempo para mejorarlo).</div><div><br /></div><div>Les dejo <a href="http://www.mediafire.com/?cbycy1pe7en">aca</a> la versión inicial. En un rato lo subo a Codeplex asi voy dejando ahi las últimas actualizaciones.</div><div><br /></div><div><br /></div><br /><a href="http://www.flickr.com/photos/82637861@N00/2207445829/" title="ZSenseMultiPlatform by PabloZaiden, on Flickr"><img src="http://farm3.static.flickr.com/2361/2207445829_954c02e2ca.jpg" width="500" height="313" alt="ZSenseMultiPlatform" /></a><br /><div><span class="Apple-style-span" style="font-style: italic;">Screenshot, corriendo el mismo ejecutable en OS X con Mono (todavía hay algunos problemas, pero anda...) y en Windows con VMWare Fusion</span></div><div><br /></div><div><br /></div><div>Un saludo!</div><div><br /></div><div>Z</div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-2214995008331864560?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com2tag:blogger.com,1999:blog-3033548414831637355.post-30686430836831521072008-01-18T20:50:00.000-02:002008-01-18T21:06:48.325-02:00Problema con parametros de tipo string de longitud 0 en Oracle usando System.Data.OracleClientHaciendo unas pruebas para una migración a Enterprise Library, nos encontramos con un problema (no se si intencional o no) utilizando las clases de acceso a datos contra Oracle que trae .NET Framework 1.1.<br /><br />Supongamos que uno quiere hacer la siguiente consulta:<br /><div style="border: 1pt solid windowtext; padding: 0pt; background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Courier New;font-size:10pt;color:black;"><br /><pre style="margin: 0px;">SELECT * FROM Countries WHERE Country_id = :c_id</pre><br /></div><br /><br />Si usamos el siguiente código, la aplicacion generará una excepcion por tener un parametro de tipo string con longitud 0:<br /><div face="Courier New" size="10pt" color="black" style="border: 1pt solid windowtext; padding: 0pt; background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"><pre style="margin: 0px;"><span style="color:blue;">using</span> (IDbConnection conn = <span style="color:blue;">new</span> OracleConnection("Password=hr;Persist Security Info=True;User ID=hr;Data Source=localhost"))</pre>{<pre style="margin: 0px;"> conn.Open();</pre><pre style="margin: 0px;"> <span style="color:blue;">using</span> (IDbCommand command = conn.CreateCommand())</pre><pre style="margin: 0px;"> {</pre><pre style="margin: 0px;"> command.CommandType = CommandType.Text;</pre><pre style="margin: 0px;"> command.CommandText = "SELECT * FROM Countries WHERE Country_id = :c_id";</pre><pre style="margin: 0px;"> </pre><pre style="margin: 0px;"> IDbDataParameter param = command.CreateParameter();</pre><pre style="margin: 0px;"> param.ParameterName = "c_id";</pre><pre style="margin: 0px;"> param.DbType = DbType.AnsiStringFixedLength;</pre><pre style="margin: 0px;"> param.Value = String.Empty;</pre><pre style="margin: 0px;"> command.Parameters.Add(param);</pre><pre style="margin: 0px;"> <span style="color:blue;">using</span> (IDataReader reader = command.ExecuteReader())</pre><pre style="margin: 0px;"> {</pre><pre style="margin: 0px;"> DumpReader(reader);</pre><pre style="margin: 0px;"> }</pre><pre style="margin: 0px;"> }</pre><pre style="margin: 0px;"> conn.Close();</pre><pre style="margin: 0px;">}</pre></div><br /><br />El error es: <span style="font-weight: bold;">Parameter 'c_id': No size set for variable length data type: String.</span><br /><br />Para solucionar esto tenemos dos opciones:<br /><br />1. Usar la librería provista por Oracle para .NET para acceder a los datos. Esta librería maneja de forma correcta los Strings vacios. (al menos es asi usando la última version de la librería. Me falta confirmar que con versiones anteriores tambien funcione)<br /><br />2. Enviar DbNull.Value como valor del parametro, en vez de String.Empty. En otro blog leí que Oracle maneja de la misma manera tanto a los strings vacíos como a los NULL. Sin embargo yo no estoy 100% seguro de que esto sea asi, asi que de tener confirmación o refutación de esto, por favor haganmelo saber! De todas maneras, mi recomendación es usar ODP.Net<br /><br /><em>Hasta la próxima!</em><br /><br /><strong>Z</strong><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3033548414831637355-3068643083683152107?l=zpodblog.blogspot.com'/></div>Zaidenhttp://www.blogger.com/profile/09059359984662336924noreply@blogger.com0