viernes, 31 de diciembre de 2010

[WP7] My Calculator

Recientemente he subido una nueva aplicación en el Marketplace de WP7. Es una calculadora científica, pensada para ingenieros informáticos. Como tal siempre he deseado tener en el móvil una calculadora en la que pudiera convertir (entre otras cosas) números de diferente base sin necesidad de usar la calculadora de Windows o el papel en su defecto. Con My Calculator puedes trabajar con el sistema decimal, radián, binario, hexadecimal y octal. Seguiré trabajando para añadirle features en el futuro. Como siempre, cualquier sugerencia será bien recibida, de igual manera si se encuentra algún bug intentaré ser lo más rápido posible en solventarlo.

calculator

La aplicación la puedes descargar aquí, por 0,99€

miércoles, 29 de diciembre de 2010

[C#] Extension Methods

Con la irrupción de LINQ, el lenguaje se debe adaptar a nuevos usos que agilicen la potencia que proporciona LINQ. Fruto de esta necesidad se incluyó en C# 3.0 los llamados “Extension Methods”. Estos métodos tienen la finalidad, como su propio nombre indica, para extender clases. Y esto puede ser interesante cuando deseo que una clase tenga determinado funcionalidad, propia de un “tipo” derivado pero sin la suficientemente intensidad para crear un tipo derivado a propósito.

Para implementarlo, es muy sencillo. Se debe crear un método estático dentro de una clase estática. A este método le pasaremos un parámetro a través del puntero this, que indica el tipo al que se asociará este método junto con los parámetros que se requieran. Por ejemplo, vamos a extender un tipo base como int con un nuevo método, que llamaremos TestInt() que comprobará cuándo el número es mayor que 0.

   1: public static class Extensions
   2:     {
   3:         public static bool TestInteger(this int number)
   4:         {
   5:             if (number > 0)
   6:             {
   7:                 return true;
   8:             }
   9:             return false;
  10:         }
  11:     }

Luego sencillamente podremos aplicar esto a todos los tipos int, siempre y cuando el acceso al namespace para que encuentre la clase Extensions. Véase el siguiente ejemplo:

   1: public class Item
   2:    {
   3:        int index;
   4:  
   5:        public Item()
   6:        {
   7:            if (index.TestInteger())
   8:            { }
   9:        }
  10:    }

Como se puede apreciar esto es algo bueno, bonito y barato, pero muy arriesgado. Se recomienda usarlo sobre nuestros tipos y siempre que sea posible dedicado a consultas de tipo LINQ o eventos. No debemos usarlo con tipos base (como es el caso) o sobre tipos que no son nuestros porque puede cambiar la implementación en el futuro y posiblemente, tengamos problemas de compatibilidad.

lunes, 27 de diciembre de 2010

[Silverlight] Convirtiendo tipos para DataTemplates

Una de las armas más poderosas de WPF y Silverlight son los DataTemplates, que te permiten especificar un template y después mediante el DataBinding puedes desplegar todos los datos de forma automática sin necesidad de rellenarlos a “pelo” insertando fila por fila.

Pero en algunas ocasiones se necesitará contemplar elementos que deben aparecer o no en función de algunos valores de lógica. Por ejemplo, en mi lógica dispongo de una clase Item que tiene una propiedad booleana llamada Borrowed. Cuando esta propiedad está a true, debe aparecer un botón, y cuando no lo está, no debe aparecer nada. En Silverlight la propiedad Visibility permite especificar la visibilidad de un elemento cualquiera, pero esta propiedad se ajusta a través de un enumerado que indica si es visible ( Visible ) o no (Collapsed). Como medida sucia podría incluir dentro de mi lógica una propiedad que tuviera ese valor, pero entonces estaría causando una dependencia entre la lógica y la interfaz de la aplicación y como todos sabemos, eso nunca es bueno. Para solventar este tipo de cosas usaremos un Converter junto con el Binding. Vayamos por partes.

Usaremos el converter para transformar el valor de una propiedad en otro. En nuestro caso, transformaremos el valor booleano de Borrowed por el valor Visible de la interfaz. Para ello crearemos una clase que implemente la interfaz IValueConverter. Esta interfaz consta de dos métodos, Convert y ConvertBack. En nuestro caso vamos a implementar únicamente el Convert, ya que el ConverBack se usará en sentido inverso (de interfaz a lógica).

   1: public class BorrowedToVisibilityConverter : System.Windows.Data.IValueConverter
   2:     {
   3:         #region IValueConverter Members
   4:  
   5:         public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   6:         {
   7:             Visibility isVisible = Visibility.Collapsed;
   8:             if ((value == null))
   9:                 return isVisible;
  10:             if (((bool)value))
  11:             {
  12:                 isVisible = Visibility.Visible;
  13:             }
  14:             return isVisible;
  15:         }
  16:  
  17:         public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  18:         {
  19:             throw new NotImplementedException();
  20:         }
  21:  
  22:         #endregion


Dentro de Convert interesa el parámetro value (lo que vamos a usar para convertir). El resto de parámetros no interesa en este caso, pero no es necesario explicarlos. Como se puede apreciar el código es sencillo, si el valor es positivo se devuelve Visibility.Visible y en cualquier otro caso se devuelve Visibiliy.Collapsed. Ahora teniendo esto ya implementado, tenemos que asociarlo a nuestro binding y por ello, a partir de este momento nos dedicamos ya con el fichero XAML correspondiente.

Ante de asociarlo, tenemos que mapear este conversor como un recurso. Para ello simplemente le asignamos una clave de referencia y especificamos el nombre del conversor:

   1: <UserControl.Resources>
   2:          <converter:BorrowedToVisibilityConverter x:Key="BorrowedToVisibility" />
   3: </UserControl.Resources>

Y por último lo asociamos a nuestro binding. En este caso irá en un botón en el su propiedad Visibility dependerá del valor de la propiedad Borrowed del binding asociado al template. Es aquí cuando ya debemos especificar el conversor de forma explícita:

   1: <Button Content="Ok!" Height="72" Width="160"  Visibility="{Binding Borrowed, Converter={StaticResource BorrowedToVisibility} }" HorizontalAlignment="Right" Click="Button_Click" Tag="{Binding Id}" Background="White" BorderBrush="Black" Foreground="Black" />

Y más en detalle:

   1: Visibility="{Binding Borrowed, Converter={StaticResource BorrowedToVisibility} }" 

Asociamos la propiedad del objeto y le indicamos que tenemos un conversor, incluido como recurso estático y su clave de referencia.

jueves, 16 de diciembre de 2010

[Ebooks] Libro GRATIS Windows Phone programming in C#

A través de Rob Miles nos cuenta que han publicado su curso de programación para Windows Phone 7 en Microsoft Faculty Center.

Windows Phone 7 Blue Book

Este libro es una introducción para Windows Phone 7 para cualquier persona que tenga fundamentos muy básicos de programación. Cuenta con ocho capítulos (WP7, Introducción a Silverlight,Introducción a Visual Studio 2010, Interfaces con Silverlight, Consumo de servicios, XNA, Creando aplicaciones para WP7 y Windows Phone Marketplace).

Descárgalo a través de este enlace. ¡Que aproveche!

[XNA/WP7] Consideraciones sobre el TouchPanel

El uso del TouchPanel es una de las características que siempre se nombran en Windows Phone 7. Y teniendo en cuenta que disponemos únicamente de tres botones físicos en el teléfono, más nos vale usar la pantalla para interactuar con el usuario. Aquí entra el TouchPanel, la pantalla táctil de los terminales del tipo Windows Phone 7.

Para usarlo es sencillo. Simplemente debemos capturar el estado del panel en el momento apropiado. Algo como lo siguiente:

   1: TouchCollection touchCollection = TouchPanel.GetState();
   2: foreach (TouchLocation tl in touchCollection)
   3: {
   4: //Aquí evaluamos cada punto...
   5: }

Capturamos el estado y mediante un bucle, recorremos todos los puntos con los que hemos hecho contacto. A ese punto se le llama un TouchLocation y el estado del TouchPanel no es más que una colección de TouchLocation. Cada TouchLocation tiene un identificador (entero), posición (Point indicando la posición de contacto) y State (para ver si está pulsado o no). Por lo tanto yo podría tener algo así:

   1: TouchCollection touchCollection = TouchPanel.GetState();
   2: foreach (TouchLocation tl in touchCollection)
   3: {
   4:     if (this.intersectsWithPlayer(tl.Position))
   5:     {
   6:         //...
   7:     }
   8: }

La función intersectsWithPlayer(Point p) comprueba si en el punto p hay una intersección con el jugador. La pregunta es, ¿es este planteamiento correcto?

No. No lo es. Y es un fallo simple y común. ¿Dónde está el fallo? El fallo es que no verifico en qué estado está el TouchLocation a analizar. Cada TouchLocation tiene varios estados (enumeración TouchLocationState): Inválido, movido, pulsado, levantado. Debemos comprobar antes de interactuar con los puntos en qué estado se encuentra, porque en ese caso el funcionamiento de la interacción no será el que deseamos. Por ejemplo, partiendo del ejemplo anterior, supongamos que ese código está dentro del Update propio y que el usuario tiene el dedo en la pantalla. En la primera iteración de Update, efectivamente el panel capturaría el estado y reconocería el punto de contacto. A continuación, sigue el ciclo de ejecución y el usuario levanta el dedo de la pantalla. ¿Qué ocurrirá en la iteración posterior de Update a ese evento? Pues volverá a capturar el punto (pero si el usuario no tiene ningún dedo puesto!!) y lo evaluará. ¿Cómo es posible que si no tenemos un punto con la pantalla el sistema diga que tiene uno? Porque evidentemente, lo tiene. Y ese punto es el punto anterior, donde antes estaba pulsado, pero con el estado “Released”. A la siguiente iteración ya no estará el punto capturado, pero previamente lo estaba por la transición de sus estados. Así que por lo tanto para solventar nuestro problemilla la solución es esta:

   1: foreach (TouchLocation tl in touchCollection)
   2: {
   3:     if ((tl.State == TouchLocationState.Pressed)
   4:     {
   5:         if ( this.intersectsWithPlayer(tl.Position))
   6:         {
   7:             //...
   8:         }
   9:     }
  10: }

Lo mismo ocurre con el resto de estados. Es un fallo que ya lo hemos sufrido varios y depurarlo es muy complicado si no tienes en cuenta esas peculiaridades de TouchLocationState.

miércoles, 1 de diciembre de 2010

[Webcast] Introducción a XNA para Windows Phone 7

Este fin de semana fue la codecamp de Windows Phone 7 en Madrid. Esta vez acudí como experto y no como programador. Previamente se creó un contenido de formación para todos los asistentes, y en mi caso me ocupé del primer webcast que sirvió de Introducción a XNA para Windows Phone 7:

image

El contenido se compone de los siguientes puntos:

  • Introducción a Windows Phone 7 desde el punto de vista del terminal.
  • Creando juegos para WP7: Explico las principales características de WP7 que soporta XNA.
  • Demo básica: Crear un proyecto desde cero y trastear con la orientación del teléfono.
  • Demo PeterBeer: Minijuego de ejemplo
  • Demos de Creators: Demos de ejemplo descargadas desde Creators para demostrar las capacidades de WP7
  • SlugKiller: Comentaré brevemente el juego que hice en la CodeCamp anterior.
  • Consejos: Dada la experiencia de la codecamp anterior, daré una serie de consejos bastante recomendables para que los asistentes a la codecamp logren llevar su proyecto al éxito.

Si quieres verlo, puedes hacerlo a través del siguiente enlace.