[Tips and Tricks] Windows Phone. ¿Dónde consigo iconos para mi App?

Introducción

Cuando desarrollamos nuestra Aplicación probablemente llegará un momento en el que necesitamos iconos.
Un buen punto de partida es el propio SDK, si el SDK de Windows Phone.
Al instalar el SDK de Windows Phone se nos añade un pequeño paquete de
iconos. Puedes encontrar el paquete de iconos en la siguiente ruta:

C:Program Files (x86)Microsoft SDKsWindows Phonev8.0Icons

Iconos SDK

Contamos con tres versiones diferentes:

  • Light. Para el tema claro contamos con iconos oscuros.
  • Dark. Para el tema oscuro contamos con iconos claros.
  • Vector. Iconos vectoriales.

Si el paquete instalado por el SDK se nos queda corto, ¿que hacemos?.
Por suerte contamos con herramientas y otros paquetes gratuitos de
iconos a nuestra disposición.

Metro Studio

Metro Studio es una herramienta  gratuita creada por SyncFusion que nos porporciona hasta 2500 iconos adaptados al estilo Metro Modern UI (perfectos para Aplicaciones Windows Phone y Windows 8).

Podemos obtener la herramienta desde el siguiente enlace.

Descargar Metro Studio

Una vez rellenado el formulario recibirás un correo electrónico con
el enlace de descarga y la clave para desbloquear la instalación del
mismo.

La herramienta:

  • Organiza los iconos por categorías.
  • Permite realizar búsquedas.
  • Permite editar los iconos (color de fondo, color del icono, forma dle fondo, etc.).
  • Gestión del tamaño, padding, márgenes, etc.
  • Rotaciones y otras transformaciones sobre el icono.
  • Permite exportar el icono a formato imagen, obtener un Path en XAML, etc.
  • Permite crear iconos nuevos personalizados según un texto y fuente seleccionada.

Usando Metro Studio

Otras fuentes

Si aun no encuentras aquel icono perfecto para tu Aplicación que andas buscando, tranquilo, hay más opciones:

  • The Noun Project:
    Es una plataforma colaborativa y comunitaria donde se crea una
    biblioteca de iconos que va creciendo día a día gracias a la ayuda de
    diseñadores de todo el mundo. La mayoría de iconos son con licencia
    Creative Commons y aquellos de pago tienen un precio muy competitivo.

  • Modern UI Icons: En este momento, paquete con 1137 iconos con estilo Modern UI:

El paquete incluye los iconos en:

  • Estilo claro.
  • Estilo oscuro.
  • Distintos formatos, PNG, Path XAML, SVG e incluso los archivos design pensados para Expression Blend!

Podéis leer el gran tutorial de uso de los iconos con Expressión Blend disponible en el siguiente enlace.

Para quien siga sin encontrar aquel icono perfecto que encaja en su
Aplicación tenéis a continuación más packs de iconos disponibles:

Más información

[Tips and Tricks] Windows Phone. Detectar si la App se ejecuta en el Emulador

Problema

El emulador de Windows Phone es una
herramienta fantástica que nos permitirá probar de manera rápida y
efectiva la aplicación que está en desarrollo sin la necesidad del
dispositivo físico pero es importante recordar, el emulador NO equivale a
un dispositivo. Hay ciertas partes de la API que no funcionan en el
emulador como algunos lanzadores u otras partes que por requisitos de
hardware tampoco lo haran como por ejemplo el uso del Bluetooth.

Podemos
gestionar estos casos en nuestros desarrollos con técnicas como las
directivas de compilación aunque poder determinar con facilidad si
estamos en el emulador o no puede ayudar en el desarrollo.

Veamos como sería…

NOTA: Podéis encontrar un listado de opciones que no se pueden realizar en el emulador en el siguiente enlace.

Solución

Dentro del namespace Microsoft.Devices tenemos la clase estática Environment.
La clase Environment proporciona información relacionada del entorno
donde se ejecuta la Aplicación. Actualmente la única propiedad con la
que cuenta es DeviceType que indica si la Aplicación se esta ejecutando en el emulador o en un dispositivo fisico:

if (Microsoft.Devices.Environment.DeviceType == Microsoft.Devices.DeviceType.Emulator)
//Emulador
else
//Dispositivo

Podéis descargar y probar un simple ejemplo que verifica si la Aplicación se ejecuta o no en el emulador:


Recordar que cualquier tipo de duda o sugerencia la podéis dejar en los comentarios.

Keep Pushing!

Más información

[Windows Phone] Creando juegos con WaveEngine. 2º Parte.

Introducción

En el artículo anterior realizamos una introducción a WaveEngine con
el objetivo de analizar el arranque y la funcionalidad básica del
engine. Para ello, nos basamos en un clásico como “Super Mario Bross”.

NOTA: “Super Mario Bross” es una marca registrada por Nintendo. Este artículo es un simple homenaje a la saga.

Tras conocer el engine, la gestion de recursos y lograr plasmar el
fondo, suelo y al personaje principal, el objetivo de esta entrada es
continuar desde el punto anterior y evolucionar el ejemplo hasta
conseguir poder mover al personaje (mediante un gamepad táctil) junto al
sistema de animaciones.

¿Te apuntas?

 

Añadiendo comportamientos

El aspecto de nuestro videojuego hasta ahora es el siguiente:

Interesante pero… ¿Mario sin correr?. Tenemos que resolver esto. Veamos como añadir animaciones a Mario.

Una animación consta de estados. Cada estado a su vez consta de varias imágenes. Tendremos dos estados:

  • Idle: Cuando Mario este parado.
  • Walk: Cuando Mario camina o corre.

Ya aprendimos a utilizar la herramienta Wave Exporter para generar
los archivos .gmk de los que se nutre el juego. Podríamos generar un gmk
para cada una de las imágenes de cada animación aunque a la larga,
penalizaría el rendimiento.

¿Qué hacemos?

La solución se llamda SpriteSheet. Un spritesheet no
es más que una imagen que contiene muchas imágenes. Se utiliza en el
juego dividiendo y obteniendo cada una de las imágenes que contiene pero
todas se obtienen del mismo fichero.

Nosotros en nuestro ejemplo vamos a utilizar el siguiente conjunto de imágenes:

Asi pues, primer objetivo, crear el spritesheet. Podríamos hacerlo a
mano con los distintos editores fotográficos conocidos aunque la tarea
es bastante tediosa.

Vamos a utilizar la herramienta TexturePacker que puedes descargar desde aquí. Abrimos la herramienta y arrastramos las imágenes anteriores:

En el lateral izquierdo tenemos el panel de configuración. El primer
cambio importante que realizaremos será elegir el formato de salida
elegido. Elegiremos “Generic XML”:

Además del spritesheet en formato PNG obtendremos un archivo en XML
que indicará el tamaño y la posición de cada una de las imágenes que
componen al spritesheet. Será importante en nuestro juego.

Finalmente, en la parte superior pulsamos el botón “Publish”:

Como resultado además del spritesheet obtenemos el XML:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with TexturePacker http://texturepacker.com-->
<!-- $TexturePacker:SmartUpdate:9253cd2deaa49622a1344586a860f75a$ -->
<!--Format:
n  => name of the sprite
x  => sprite x pos in texture
y  => sprite y pos in texture
w  => sprite width (may be trimmed)
h  => sprite height (may be trimmed)
oX => sprite's x-corner offset (only available if trimmed)
oY => sprite's y-corner offset (only available if trimmed)
oW => sprite's original width (only available if trimmed)
oH => sprite's original height (only available if trimmed)
r => 'y' only set if sprite is rotated
-->
<TextureAtlas imagePath="Mario.png" width="64" height="128">
     <sprite n="0.png" x="2" y="2" w="17" h="27"/>
     <sprite n="1.png" x="21" y="2" w="17" h="28"/>
     <sprite n="2.png" x="40" y="2" w="15" h="28"/>
     <sprite n="3.png" x="2" y="32" w="17" h="28"/>
     <sprite n="4.png" x="21" y="32" w="15" h="28"/>
     <sprite n="5.png" x="38" y="32" w="17" h="28"/>
     <sprite n="6.png" x="2" y="62" w="17" h="27"/>
</TextureAtlas>

Como podéis observar en el archivo XML, contiene la posición de cada
una de las imágenes junto a su tamaño. Todo listo para comenzar!

Vamos a añadir el spritesheet y el XML en el proyecto pero … espera!.
No directamente, recuerda que tenemos que utilizar la herramienta Wave
Exporter para generar el archivo .gmk:

Nos centramos en la entidad Mario. El principal cambio con respecto a lo
que teníamos hasta ahora será la introducción del componente de tipo Animation2D. El componente Animation2D nos permite definir desde una hasta un conjunto de animaciones:

var mario = new Entity("Mario")
.AddComponent(new Transform2D()
{
     X = WaveServices.Platform.ScreenWidth / 2,
     Y = WaveServices.Platform.ScreenHeight - 46,
     Origin = new Vector2(0.5f, 1)
})
.AddComponent(new Sprite("Content/Mario.wpk"))
.AddComponent(Animation2D.Create<TexturePackerGenericXml>("Content/Mario.xml")
.Add("Idle", new SpriteSheetAnimationSequence() { First = 3, Length = 1, FramesPerSecond = 11 })
.Add("Running", new SpriteSheetAnimationSequence() { First = 0, Length = 3, FramesPerSecond = 27 }))
.AddComponent(new AnimatedSpriteRenderer(DefaultLayers.Alpha));

Nosotros necesitamos por ahora al menos dos conjuntos de animaciones
(Mario en estado Idle y Mario en estado Running). Todo ello recordar
utilizando el mismo sprite sheet.

Antes de continuar, analicemos el código anterior. Para crear la animación utilizamos el método estático Animation2D.Create
que recibe un parámetro genérico (generalmente una clase, en nuestro
ejemplo TexturePackerGenericXml) donde se definirá cada sprite
perteneciente al spritesheet utilizado en la animación.  Una vez creado
el Animation2D definimos todas las animaciones que contendrá. En nuestro
caso definimos las dos necesarias (Idle i Running).

En cada animación definida establecemos un nombre junto a un objeto de tipo SpriteSheetAnimationSecuence que definirá el frame inicial de la animación, el frame final y el número de frames a renderizar por segundo.

Continuamos. Antes de avanzar, es importante que no se nos pase añadir la entidad a escena:

EntityManager.Add(mario);

Bien, si ejecutamos en este momento… ops!, no hay cambios.
Efectivamente, hemos añadido a Mario animaciones para cuando este parado
y para cuando corra pero no tenemos forma de cambiar entre los estados,
es decir, aun no somos capaces de hacer correr a Mario.

Pongamos fin a este problema. Vamos a crear un behavior, en nuestro
ejemplo llamado MarioBehavior, que nos permitirá desplazar a Mario
horizontalmente. Este Behavior capturará las pulsaciones  en la pantalla
táctil para permitir modificar el estado de Mario y asi permitir el
desplazamiento:

protected override void Update(TimeSpan gameTime)
{
     currentState = AnimState.Idle;
 
     // touch panel
     var touches = WaveServices.Input.TouchPanelState;
     if (touches.Count > 0)
     {
          var firstTouch = touches[0];
          if (firstTouch.Position.X > WaveServices.Platform.ScreenWidth / 2)
          {
               currentState = AnimState.Right;
          }
          else
          {
               currentState = AnimState.Left;
          }
     }
 
     // Set current animation if that one is diferent
     if (currentState != lastState)
     {
          switch (currentState)
          {
               case AnimState.Idle:
                    anim2D.CurrentAnimation = "Idle";
                    anim2D.Play(true);
                    direction = NONE;
                    break;
               case AnimState.Right:
                    anim2D.CurrentAnimation = "Running";
                    trans2D.Effect = SpriteEffects.None;
                    anim2D.Play(true);
                    direction = RIGHT;
                    break;
               case AnimState.Left:
                    anim2D.CurrentAnimation = "Running";
                    trans2D.Effect = SpriteEffects.FlipHorizontally;
                    anim2D.Play(true);
                    direction = LEFT;
                    break;
          }
     }
 
     lastState = currentState;
 
     // Move sprite
     trans2D.X += direction * SPEED * (gameTime.Milliseconds / 10);
 
     // Check borders
     if (trans2D.X < BORDER_OFFSET)
          trans2D.X = BORDER_OFFSET;
     else if (trans2D.X > WaveServices.Platform.ScreenWidth - BORDER_OFFSET)
          trans2D.X = WaveServices.Platform.ScreenWidth - BORDER_OFFSET;
}

En la parte superior tenéis el código implementado en el método Update. En el método se realizan varias tareas fundamentales:

  • Captura las pulsaciones en la pantalla (izquierda y derecha).
  • Modifica el estado de la animación a la adecuada (dependiendo del valor de currentState).
  • Se mueve el sprite a la posición correspondiente.
  • Se verifica que el sprite este dentro de los márgenes.

Llegados a este punto lo tenemos todo casi preparado para ver correr
por fin a Mario pero… espera!. Debemos modificar la instancia de Mario
para añadirle el Behavior:

AddComponent(new MarioBehavior())

Ahora si!. Si ejecutamos y pulsamos en el lateral izquierdo Mario
correrá hacia la izquierda hasta el márgen izquierdo como máximo y
exactamente igual en sentido contrario. Genial, ¿cierto?. Aunque…
llevamos toda la vida jugando con Mario con una cruceta, ¿como lo
solucionamos?.

Bueno, ningun dispositivo Windows Phone cuenta con botones físicos
específicos para juegos. Sin embargo, tenemos una maravillosa pantalla
táctil con todas las posibilidades que ofrece.

¿Que tal si implementamos una cruceta virtual?.

Manos a la obra. Lo primero que debemos hacer es… tener unos gráficos
de nuestra cruceta para mostrar en pantalla. Asi que tenemos que crear
nuestro wpk correspondiente. Una vez añadido al proyecto, tenemos que
instanciarlo:

var joystick = new Entity("joystick")
.AddComponent(new Sprite("Content/Joystick.wpk"))
.AddComponent(new SpriteRenderer(DefaultLayers.Alpha))
.AddComponent(new Transform2D()
{
     X = joystickOffset,
     Y = WaveServices.Platform.ScreenHeight - joystickOffset - 300
});
De esta forma lograremosque la cruceta aparezca en la zona inferior
izquierda de la pantalla para molestar lo mínimo posible al jugador. La
añadimos a escena:
EntityManager.Add(joystick);
De momento, si pulsamos cualquier dirección de la cruceta, no hace nada…
¿no echáis en falta algo?. Tenemos que añadir comportamiento a la
cruceta digital asi que debemos crear un nuevo Behavior. Creamos un
Behavior llamado JoyStickBehavior:
protected override void Update(TimeSpan gameTime)
{
     this.UpPressed = this.DownPressed = this.LeftPressed = this.RightPressed = false;
 
     var touchState = WaveServices.Input.TouchPanelState;
 
     if (touchState.Count > 0)
     {
          var touch = touchState[0];
 
          // Up/down check
          if (touch.Position.X > (trans2D.X + 100) && touch.Position.X < (trans2D.X + 200))
          {
               // Here we're inside the vertical area defined by up/down buttons, let's check which one of those
               if (touch.Position.Y > trans2D.Y && touch.Position.Y < (trans2D.Y + 100))
               {
                    // Up
                    this.UpPressed = true;
               }
               else if (touch.Position.Y > (trans2D.Y + 200) && touch.Position.Y < (trans2D.Y + 300))
               {
                    // Down
                    this.DownPressed = true;
               }
          }
          // Left/right check
          else if (touch.Position.Y > (trans2D.Y + 100) && touch.Position.Y < (trans2D.Y + 200))
          {
               // Here we're inside the horizontal area defined by left/right buttons, let's check which one of those
               if (touch.Position.X > trans2D.X && touch.Position.X < (trans2D.X + 100))
               {
                    // Left
                    this.LeftPressed = true;
               }
               else if (touch.Position.X > (trans2D.X + 200) && touch.Position.X < (trans2D.X + 300))
               {
                    // Right
                   this.RightPressed = true;
               }
          }
     }
}
Basicamente detectamos si  el usuario toca en la cruceta. Modificamos el
Behavior MarioBehavior para añadir una instancia del Behavior Joystick y
detectar si tenemos que cambiar a Mario de estado según el estado del
Joystick:
protected override void Update(TimeSpan gameTime)
{
     currentState = AnimState.Idle;
 
     // touch panel
     if (joystick.RightPressed)
     {
          currentState = AnimState.Right;
     }
 
     if(joystick.LeftPressed)
     {
          currentState = AnimState.Left;
     }
 
     // Set current animation if that one is diferent
     if (currentState != lastState)
     {
          switch (currentState)
          {
               case AnimState.Idle:
                    anim2D.CurrentAnimation = "Idle";
                    anim2D.Play(true);
                    direction = NONE;
                    break;
               case AnimState.Right:
                    anim2D.CurrentAnimation = "Running";
                    trans2D.Effect = SpriteEffects.None;
                    anim2D.Play(true);
                    direction = RIGHT;
                    break;
               case AnimState.Left:
                    anim2D.CurrentAnimation = "Running";
                    trans2D.Effect = SpriteEffects.FlipHorizontally;
                    anim2D.Play(true);
                    direction = LEFT;
                    break;
          }
     }
 
     lastState = currentState;
 
     // Move sprite
     trans2D.X += direction * SPEED * (gameTime.Milliseconds / 10);
 
     // Check borders
     if (trans2D.X < BORDER_OFFSET)
          trans2D.X = BORDER_OFFSET;
     else if (trans2D.X > WaveServices.Platform.ScreenWidth - BORDER_OFFSET)
          trans2D.X = WaveServices.Platform.ScreenWidth - BORDER_OFFSET;
}
Añadimos a la instancia Mario el Behavior del Joystick:
AddComponent(new MarioBehavior(EntityManager.Find("joystick")))
La instancia Mario por lo tanto quedaría:
var mario = new Entity("Mario")
.AddComponent(new Transform2D()
{
     X = WaveServices.Platform.ScreenWidth / 2,
     Y = WaveServices.Platform.ScreenHeight - 46,
     Origin = new Vector2(0.5f, 1)
})
.AddComponent(new Sprite("Content/Mario.wpk"))
.AddComponent(Animation2D.Create<TexturePackerGenericXml>("Content/Mario.xml")
.Add("Idle", new SpriteSheetAnimationSequence() { First = 3, Length = 1, FramesPerSecond = 11 })
.Add("Running", new SpriteSheetAnimationSequence() { First = 0, Length = 3, FramesPerSecond = 27 }))
.AddComponent(new AnimatedSpriteRenderer(DefaultLayers.Alpha))
.AddComponent(new MarioBehavior(EntityManager.Find("joystick")));

Si ejecutamos ahora nuestro juego podemos probar que efectivamente
pulsando en la cruceta el lateral izquierdo Mario corre a la izquierda y
exactamente lo mismo en dirección opuesta ocure si pulsamos la derecha.

Convirtiendo el proyecto a Windows Phone

Pero… espera…el proyecto es una aplicación Windows de escritorio, ¿no ibamos a desarrollar el juego para Windows Phone?

Esto… efectivamente. Vamos a descubrir a continuación una de las
grandes características que ofrece el engine que no es otra que poder
convertir nuestro proyecto a las siguientes plataformas:

  • Windows Phone 7/8. Por ahora es un proyecto Windows Phone 7. Por compatibilidad binaria funciona sin problemas en Windows Phone 8.
  • IOS (iPhone, iPad & iPod Touch),
  • Windows 8 (Aplicación Windows Store).
  • Android.

NOTA: La herramienta la podéis encontrar dentro de una carpeta llamada “Tools” en el directorio de instalación.

¿Cómo la utilizamos?

Muy fácil. Pulsamos el botón Open para seleccionar la solución
(archivo .sln) a convertir. Marcamos las casillas de las plataformas que
deseamos como destino y pulsamos el boton Convert.

Una vez que termina la conversión si nos dirigimos al directorio de
la solción tendremos una nueva solución mas su carpeta asociada por cada
casilla marcada (plataforma destino).

Listo!.

¿Ya?. Casi. Las soluciones estan practicamente listas a falta de los
recursos (nuestro archivos wpk). Podemos reutilizar los ya utilizados o
podemos crear nuevos archivos de recursos adaptados a las nuevas
plataformas.

NOTA: Recordar establecer el valor Content en la propiedad Build Action.

Tras añadir los recursos, podemos ejecutar el proyecto convertido en
el emulador de Windows Phone o en un dispositivo físico donde podremos
probar nuestro juego!

En nuestro caso hemos convertido la solución a un proyecto Windows
Phone. Le hemos añadido y a continuación tenéis disponible el resultado:

Podéis ver a continuación un video del juego en funcionamiento en el siguiente enlace.

Espero que lo visto en la entrada os haya resultado interesante.
Recordar que cualquier duda o sugerencia la podéis dejar en los
comentarios de la entrada.

Extra

Es sumamente recomendable que utilicéis la herramienta Sample Browser.
Es una herramienta extra de los chicos de Wave Engine que nos permite
ver y descargar una gran cantidad de ejemplos realizados con el motor.
Una fuente sin duda excelente de aprendizaje. Todo lo visto en esta
entrada esta perfectamente cubierto en los ejemplos. Muy recomendado!

Conclusiones

Estamos ante un engine joven pero lo suficientemente sólido como para
desarrollar juegos de peso. Es gratuito, nos permite desarrollar bajo
C# y además podemos exportar nuestros juegos a multitud de plataformas.
Sin duda, gran trabajo el realizado hasta ahora por el equipo de Wave
Engine con actualizaciones periódicas constantes afinando poco a poco el
engine.

Keep Pushing!

Más información

Extendiendo el código generado en Windows Phone App Studio

Introducción

Previamente ya habíamos hablado de Windows Phone App Studio, nueva herramienta online que permite crear aplicaciones de calidad para Windows Phone 8 en cuestión de minutos.Entre sus principales características hay muchas destacables:

  • Permite crear aplicaciones Windows Phone sin tener conocimientos de desarollo.
  • Las Aplicaciones se generan en código nativo.
  • Permite instalar directamente la Aplicación sin requerir cuentas extras de ningun tipo.
  • Permite compartir la Aplicación creada con amigos.

App Studio

Sin embargo, la característica principal del sistema, es que puedes descargar el código fuente
de la Aplicación. Esto permite extender el código fuente añadiendo
nuevas características. En esta entrada vamos a analizar la estructura y
técnicas utilizadas en el código generado asi como aprener como
extenderlo con facilidad.

¿Te apuntas?

Echemos un vistazo al código…

Una vez generamos nuestra Aplicación desde Windows Phone App Studio veremos una pantalla similar a la siguiente:

Descargar el código fuente

Desde este apartado podemos:

  • Instalar nuestra Aplicación en un dispositivo para probarla de manera fácil leyendo un simple código QR.
  • Compartir vía email nuestra Aplicación con amigos.
  • Descargar el paquete de publicación (el XAP ya empaquetado listo para publicar).
  • Y por último, podemos descargar el código fuente!

Descargamos el código fuente de nuestra Aplicación:

Descomprimimos y abrimos la solución (Solution.sln) en Visual Studio.

NOTA: El proyecto es una solución para Windows Phone 8 que requiere Visual Studio 2012.

De un primer vistazo a la estructura de la solución podemos ver que la solución esta organizada en diferentes proyectos:Estructura

WP8App: Este proyecto es la Aplicación Windows Phone 8 en si. Implementa el patrón MVVM junto a otras técnicas y buenas prácticas (Ioc, servicios, etc) de los que hablaremos con calma más adelante.
Entities: Entidades utilizadas en la Aplicación. Las entidades implementan una iterfaz BindableBase que es una implementación de la interfaz INotifyPropertyChanged.
Repositories: En este proyecto tenemos disponibles todos repositorios de información utilizados por la Aplicación.

Esta
separación de responsabilidades en proyectos independientes nos permite
extender con mayor facilidad cada una de las partes implicadas asi como
la creación de test unitarios que se encargen de asegurar la calidad y
funcionamiento de todo.

 

Profundizamos en la estructura del proyecto Windows Phone:

Lo primero que llama la atención a simple vista es la implementación del patrón MVVM en el proyecto. Model-View-ViewModel (MVVM) es un patrón de diseño de aplicaciones que permite desacoplar el código de interfaz de usuario del código que no sea de interfaz de usuario.

El patrón MVVM se compone de tres partes fundamentales:

La Vista (View):
Define las vistas de la aplicación, es decir, conjunto de controles,
layout, estilos, etc. Se nutre del vista-modelo utilizando su propiedad DataContext.
Los controles se configuran mediante propiedades expuestas por el
vista-modelo e interactuan mediante el uso de comandos. Todas las vistas
están situadas dentro de la carpeta View.
El Vista-Modelo (ViewModel):
Conjunto de clases que encapsulan la lógica de presentación. Implementa
propiedades y comandos a los que se asociará la vista. Controla la
interacción de la vista con el modelo. Todos los viewmodels están
organizados dentro de la carpeta ViewModel.
El Modelo (Model):
Conjunto de clases que encapsulan los datos de la aplicación junto a su
lógica de negocio. Validan el modelo de los datos aplicando reglas de
negocio. El modelo suele implementar las interfaces INotifyPropertyChanged y INotifyCollectionChanged
para notificar cambios en propiedades y colecciones. No deben
referenciar a la vista ni al vista-modelo. En nuestra solución, tenemos
los modelos dentro del proyecto Entities (recordar que implementan la interfaz) .

A vista de pájaro ya hemos analizado la estructura del proyecto, sin embargo, creo que merece la pena que pronfundizemos más.

Con
el objetivo en mente se poder extender y reutilizar el código en la
medida de lo posible, se evita añadir código específico de la plataforma
en los viewmodels. No podemos utilizar directamente APIs de Windows
Phone en nuestros viewmodels.

¿Porque?

Hay varios motivos
para ello. Por ejemplo, si queremos portar la Aplicación a Windows 8
utilizaremos una Portable Library. Los viewmodels son candidatos
perfectos para migrar a la clase portable pero no podemos hacerlo con
código específico de la plataforma.

¿Cómo lo conseguimos?

Las operaciones que necesitemos en nuestra aplicación que requieran acceder a las APIs de Windows Phone las implementaremos en servicios. Podemos encontrar los servicios en la carpeta Services del proyecto.

Dependiendo
de los extras y otro tipo de configuraciones aplicadas en el portal
durante el proceso de creación de la Aplicación, podemos contar con los
siguientes servicios:

DialogService. Lo utilizamos para mostrar notificaciones en nuestra aplicación mediante Messagebox.
LiveTileService. El nombre deja pocas dudas. Lo utilizamos para la gestión de tiles en la aplicación, crear y eliminar tiles secundarios.
NavigationService. Utilizamos el servicio NavigationService para realizar la navegación entre páginas.
ReminderService. Nos permite crear recordatorios.
ShareService. Nos permite compartir información (Lanzador EmailComposeTask).
LockScreenService. Nos permite modificar la imagen utilizada en la LockScreen.
SpeechService. Nos permite utilizar TTS en nuestra Aplicación.
WebBrowserService. Abre una URL en el navegador (Lanzador WebBrowserTask).

Los viewmodels implementan los servicios gracias al uso de Ioc (Inversion of Control) por DI
(Dependency Injection). Se crea un contenedor donde registramos todos
los servicios que vamos a utilizar junto a los viewmodels que utilizarán
las vistas y que accederán a los servicios utilizando interfaces.

Para ello, se utiliza Unity v2.1,
el contenedor IoC de Patterns & Practices. Contamos con un service
locator (ViewModelLocator) que utilizará el contenedor creado. Está
instanciado en App.xaml y se utiliza para que cada vista pueda acceder a
la instancia de su viewmodel correspondiente cada vez que lo necesite.
Los viewmodels a su vez  accederán a los servicios utilizando
interfaces.

Llegados a este punto y tras analizar la estructura y
técnicas utilizadas en el código generado de nuestra aplicación podemos
deducir que:

  • El código generado implementa el patrón MVVM y
    utiliza conceptos y buenas prácticas como Ioc, servicios o la
    abstracción de implementaciones gracias a interfaces creando un código de calidad, además facilmente extensible.
  • El
    código viene en líneas generables perfectamente preparado para
    implementar test con facilidad o utilizar Portable Library y migrar
    nuestra aplicación a otras plataformas.
  • Para enriquecer nuestras
    vistas se utilizan algunas de las herramientas más conocidas en el
    entorno de desarrollo Windows Phone como el Toolkit o MyToolkit. Para 
    facilitar la gestión de dichas librerías se incluyen paquetes NuGet.

Asi que, analizada la estructura del código generado, ¿que tal si lo extendemos?

Extendiendo el código

Manos a la obra. Vamos a extender el código de la Aplicación generada. Para probar las múltiples opciones a realizar, vamos a:

  • Modificar uno de los servicios ya existentes para modificar la implementación del mismo.
  • Añadir un nuevo servicio que añada nueva funcionalidad a al Aplicación.

Comenzamos modificando uno de los servicios existentes. Nos centramos por ejemplo en el servicio DialogService  que utilizamos para mostrar notificaciones en nuestra aplicación mediante Messagebox:

public class DialogService : IDialogService
{
public void Show(string message)
{
MessageBox.Show(message);
}

public void Show(string message, string caption)
{
MessageBox.Show(message, caption, MessageBoxButton.OK);
}
}

Contamos
con las librerías del Windows Phone Toolkit incluidas en el proyecto.
Por lo tanto, podemos extender el servicio utilizando un control más
versátil como el CustomMessageBox perteneciente al Toolkit. Para ello,
en la misma clase, añadimos la referencia necesaria para poder utilizar
el control:

using Microsoft.Phone.Controls;

Reemplazamos la lógica de cada método:


public void Show(string message)
{
CustomMessageBox messageBox = new CustomMessageBox()
{
Message = message
};

messageBox.Show();
}

public void Show(string message, string caption)
{
CustomMessageBox messageBox = new CustomMessageBox()
{
Caption = caption,
Message = message
};

messageBox.Show();
}

Fácil,
¿verdad?. Por supuesto, podemos añadir más métodos al servicio
(recordar en dicho caso incluirlas en la interfaz) permitiendo confgurar
el botón derecho, el botón izquierdo, el contenido del mensaje (en este
control tenemos muchas posibilidades como por ejemplo incluir hasta un
Pivot como contenido), etc.

De acuerdo, hemos modificado algo
bastante simple. ¿Que pasa si deseamos añadir nueva funcionalidad a la
ya existente?. No dista mucho de lo ya realizado. Vamos a añadir un
nuevo servicio. Una acción bastante común en Aplicaciones Windows Phone
que acceden a información alojada en un servidor suele ser cachear la
información. Para ello, una buena opción es utilizar el Isolated
Storage.

Como el acceso al Isolated Storage es una funcionalidad
específica de la plataforma… si, efectivamente, va a los servicios.
Creamos entonces un servicio llamado StorageService.

Creamos la interfaz que define al servicio:

public interface IStorageService
{
T Load<T>(string fileName);
bool Save<T>(string fileName, T data);
}

Como
podéis ver muy sencilla. Tendrá un método Load que pasado un  nombre de
achivo devolverá la información almacenada y otro método Save que
tendrá como parámetros el nombre del archivo junto a la información a
almacenar.

Implementamos la interfaz:

public class StorageService : IStorageService
{

}

Creamos la clase que implementa la interfaz:

public T Load<T>(string fileName)
{
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!myIsolatedStorage.FileExists(fileName))
return default(T);

using (IsolatedStorageFileStream stream = myIsolatedStorage.OpenFile(fileName, FileMode.Open))
{
var xml = new XmlSerializer(typeof(T));
T data = (T)xml.Deserialize(stream);
return data;
}
}
}

public bool Save<T>(string fileName, T data)
{
try
{
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile(fileName))
{
var xml = new XmlSerializer(typeof(T));
xml.Serialize(fileStream, data);
}
}

return true;
}
catch
{
return false;
}
}

El siguiente paso necesario será el registrar este servicio en nuestro contenedor de Ioc:

_currentContainer.RegisterType<IStorageService, StorageService>();

Por último, podemos utilizar nuestro servicio en un viewmodel por ejemplo muy facilmente:

private IStorageService _storageService;

En el contructor instanciamos los servicios:

public TheTeam_AlbumViewModel(IDialogService dialogService, INavigationService navigationService,
ILockScreenService lockScreenService, ITheGuysCollection theGuysCollection,
IawardsCollection awardsCollection, IvideosDataSource videosDataSource,
IblogDataSource blogDataSource, IStorageService storageService)
{
_dialogService = dialogService;
_navigationService = navigationService;
_lockScreenService = lockScreenService;
_theGuysCollection = theGuysCollection;
_awardsCollection = awardsCollection;
_videosDataSource = videosDataSource;
_blogDataSource = blogDataSource;
_storageService = storageService;
}

Y lo podemos utilizar por ejemplo, al obtener una colección de elementos:

_storageService.Save<ObservableCollection<RssSearchResult>>("Blog_NewsListControlCollection", Blog_NewsListControlCollection);

De
esta forma podemos almacenar en el almacenamiento aislado la
información del servidor. Si el usuario vuelve inmediatamente a ver la
misma información pdríamos recueperar la existente en lugar de volver a
realizar la petición al servidor.

Podéis echarle un vistazo al código generado (asi como las extensiones realizadas) descargando el ejemplo disponible desde el siguiente enlace.

En definitiva, el tener acceso al código nativo nos permite extender el código a nuestras propias necesidades.

Conclusiones

El
código generado implementa el patrón MVVM y utiliza conceptos y buenas
prácticas como Ioc, servicios o la abstracción de implementaciones
gracias a interfaces creando un código de calidad que como hemos podido verificar es facilmente extensible.

En
las plantillas de Visual Studio para Windows Phone se está extendiendo
el uso del patrón MVVM junto a otras buenas prácticas. Que el código
generado por Windows Phone App Studio haga uso de todas las buenas
prácticas y recomendaciones en el desarrollo Windows Phone es un punto
positivo que permite no solo ayudar a cualquier usuario a crear su
Aplicación para Windows Phone sino contribuir también en el aprendizaje
en el desarrollo de la plataforma mostrando los beneficios de estas
técnicas desde el principio.

Más información

Windows Phone App Studio ya disponible!

Crear Aplicaciones

De eso se trata. El crear las mejores y más atractivas aplicaciones
móviles posibles. Al fin y al cabo cada entrada de este modesto blog
tiene como objetivo aportar un granito de arena en lo posible. Nos
esforzamos día a día en crear las mejores aplicaciones posibles. Sin
embargo, el tiempo, ese fatidico enemigo que nos acosa constantemente,
es un riesgo común a la hora de crear aplicaciones. Proyectos que se
escapan por no cubrir las necesidades de la aplicación en el tiempo
deseado, por no llegar económicamente a poder gestionarlo o simplemente
porque el cliente desea ver un prototipo inicial que no podemos costear.

¿Y si tuviesemos una herramienta que nos solucionase todos esos problemas?

No, la magia no existe, pero si que acaba de lanzarse el servicio Windows Phone App Studio que nos permite crear aplicaciones de calidad para Windows Phone 8 en cuestión de minutos!

App Studio

¿Qué es Windows Phone App Studio?

Imagina la posibilidad de
crear prototipos en cuestión de minutos y poder enseñarselos al cliente
directamente desde el teléfono, o crear la base de tu aplicación y luego
poder continuarla tu mismo, si continuarla tu mismo, porque una de las
características principales del servicio es que permite descarga el código fuente de la aplicación generada!

Windows
Phone App Studio es un servicio al que accedemos a un portal web. Desde
el portal podemos crear aplicaciones para Windows Phone 8 mediante un
simple asistente de solo cuatro pasos.

Una vez creada la aplicación podremos probarla directamente en el
teléfono con tan solo leer un código QR, compartir el enlace a la
aplicación con amigos o descarga el código fuente de nuestra aplicación.
El código fuente contiene toda la estructura del proyecto con los
recursos incluidos respetando las guías de estilo y diseño además de
cuidar buenas prácticas en la organización del proyecto utilizando MVVM,
Ioc, separación de la lógica propia del sistema en servicios, etc.
Profundizaremos en este punto un poco más adelante.

Suena interesante, ¿verdad?

Un Tour por Windows Phone App Studio

Vamos a realizar un pequeño Tour paso a paso creando nuestra propia aplicación. Comenzamos!

El primer paso, elegir si partimos desde cero o desde una plantilla:

¿Plantillas?

El concepto es fácil. Podemos buscar similitudes
en la creación de documentos Word. Podemos partir de un documento vacío o
utilizar cualquiera de las plantillas de documentos que nos vienen
incluidas para crear calendarios, cartas, etc.

En este caso,
podemos partir desde una aplicación vacía que no contendrá nada o
utilizar una de las múltiples plantillas con las que cuenta App Studio
que se adapte a nuestras necesidades.

En este caso he decidido realizar una aplicación sobre Channel 9,
fantástico portal con videos relacionados con tecnologías Microsoft.
Para ello partiré de una de las plantillas, concretamente la de «Video
Channels»:

Vemos la descripción de la plantilla asi como unas capturas que nos
muestran el resultado de la misma. Pulsamos en botón «Create App» y
comenzamos!

Primer paso, «1ºApp Information», definir la información base de la aplicación:

  • Título: El título de la Aplicación. Se colocará en la cabecera de la Aplicación.
  • Descripción: Descripción de la Aplicación.
  • Icono: Icono de la Aplicación. Se utiliza en la cabecera de la Aplicación asi como en los Tiles.

Nótese
que cada cambio realizado en la configuración de la Aplicación tiene
reflejo sobre el simulador HTML situado en la parte derecha:

Primer paso

Todo listo, nada más que hacer aqui, pasamos al segundo paso, «2º Configure App Content»:

Segundo paso

Desde esta sección podemos gestionar todo el contenido
de nuestra aplicación. La aplicación (plantilla seleccionada) cuenta
con 5 secciones organizadas en formato Panorama en la Aplicación (cada
sección corresponde con un PanoramaItem). Dentro de cada sección contamos con un conjunto de páginas que se abastecen de uno o más datasources.

Los DataSources
de la aplicación los tenemos situados en la parte izquierda. Contamos
con diferentes tipos de datasources a utilizar en nuestras aplicaciones:

  • Estático: Datos gestionados por nosotros mismos que serán incrustados como recurso en nuestra aplicación.
  • AppStudio:
    Datos gestionados por nosotros mismos pero a diferencia de los
    anteriores se almacenan en la nube. No hace falta actualizar la
    aplicación para actualizar la información.
  • RSS: Datos obtenidos de una URL RSS.
  • YouTube: Datos obtenidos de una búsqueda realizada en YouTube mediante un parámetro.
  • HTML: Información en formato HTML.

Haciendo clic sobre uno de los datasources entramos en modo edición del mismo:

DataSource

Volviendo a la vista principal del segundo paso, vamos a gestionar las
secciones. En la parte superior izquierda contamos con botones que nos
permiten editar o eliminar las secciones existentes:

En nuestro ejemplo, eliminamos todas las secciones exceptuando «channel9» y «about».

En la gestión de una sección podemos, cambiar el nombre de la sección además de poder añadir o quitar páginas:

NOTA: Por supuesto, podemos añadir nuevas secciones a nuestra aplicación. Contamos con cuatro tipos diferentes de secciones:

  • Collection: Sección que cuenta con un DataSource estático y nos añade por defecto un par de páginas formando un maestro-detalle.
  • RSS: Sección que cuenta con un DataSource RSS y nos añade por defecto un par de páginas formando un maestro-detalle.
  • YouTube: Sección que cuenta con un DataSource YouTube y nos añade por defecto un par de páginas formando un maestro-detalle.
  • HTML: Sección que cuenta con un DataSource HTML y nos añade por defecto una única página.

Además
de gestionar los datasources y las secciones, podemos gestionar las
páginas de una sección. Haciendo clic en una de las páginas de una
sección:

En la edición de páginas podemos modificar el título de la página, el
Layout de la página y entra en juego un concepto bastante versátil e
interesante, los Bindings. Cada Layout cuenta con un
conjunto de posibles valores que podemos vincular a cada uno de los
campos correspondientes a un elemento de nuestro DataSource.

En
definitiva, el segundo paso es el paso de mayor importancia del
asistente. Nos permite gestionar el contenido de nuestra aplicación.
Partimos creando una sección de un determinado tipo según el tipo de
información a utilizar. Esto nos crea por defecto un datasource y entre
una y varias páginas. Podemos gestionar múltiples secciones configurando
el Panorama principal de la Aplicación.

NOTA: Al
añadir sección se permite también añadir un Menu. NO siempre crearemos
aplicaciones tipo Panorama con n PanoramaItems por sección. Podemos
tener un simple menu, un Panorama con un menu, etc. Nos hemos centrado
para introducir App Studio en un caso simple.

Una vez configurado
el contenido de nuestra Aplicación, un conjunto de videos del canal
oficial de YouTube y una vista con Información acerca de Channel9,
continuamos al siguiente paso.

Tercer paso, «3º Configure App Style», donde configuraremos principalmente la apariencia de la Aplicación:

Desde este paso del asistente gestionamos tres puntos importantes de nuestra Aplicación (organizados por pestañas):

  • style: Desde
    este apartado configuramos los parámetros que afectan a la apariencia
    general de la Aplicación, el color de la fuente, el color o imagen de
    fondo, el color del ApplicationBar…
  • tiles: Desde
    este apartado elegimos que tipo de plantilla utilizamos en nuestro Tile
    de Aplicación (Cycle, Iconic o Flip) además de configurar el contenido
    del mismo.
  • splash & lock: En este apartado elegimos que imagen de splash y de lock screen utilizaremos en caso necesario en nuestra Aplicación.

¿Tenemos la apariencia de nuestra Aplicación bien definida?. Pasamos al último paso, «4º Summary»:

En este paso se nos muestra un resumen de nuestra Aplicación antes de
generar la misma. Es momento de revisar que el número de secciones,
páginas y datasources encajan con lo que teníamos en mente. Además en
este punto tomamos una decisión importante.

¿Recuerdas las
plantillas que vimos al comienzo antes de comenzar?. Tenemos la
posibilidad de hacer nuestra aplicación pública. De este modo al resto
de usuarios de App Studio le aparecerá la misma como plantilla
contribuyendo con la comunidad permitiendo crear cada vez aplicaciones
más completas y atractivas.

Para generar la Aplicación basta con pulsar el botón «Generate»:

Tras unos breves segundos tendremos nuestra Aplicación generada:

Probando nuestra Aplicación en el teléfono!

Una vez tenemos
la Aplicación generada podemos probarla directamente desde el teléfono
móvil. El primer paso es instalar el certificado Windows Phone App Studio certificate. Lo podemos hacer escaneándo su código QR:

NOTA: Este certificado sólo lo tenemos que instalar una única vez.

Tras instalar el certificado, podemos leer el código QR de nuestra aplicación para proceder a su instalación.

El Dashboard

Segun
vayamos creando aplicaciones sería fantástico  contar con un historial
que nos permita visualizar que aplicaciones hemos realizado asi como
poder gestionarlas. De hecho, existe, se llama DashBoard:

Seleccionando una Aplicación podemos obtener información detallada de
la misma además de poder realizar múltiples acciones como editarla,
descargar el código fuente, instalarla, o eliminarla.

Más Información

<Greeting Title="Hola" Type="geeks.ms" />

Me siento tremendamente orgulloso de poder inaugurar este blog. Para aquellos que no me conozcáis, deciros que llevo tiempo publicando artículos en http://javiersuarezruiz.wordpress.com y que, gracias a Rodrigo Corral entre otros, puedo dar el salto a geeks.ms. Mis inquietudes se mueven por el mundo XAML, Windows 8 y Windows Phone principalmente por lo que la mayoría de artículos se centrarán en dicha temática. También escribiré algunos artículos de otras temáticas asi como intentar comunicar posibles eventos o lanzamientos que puedan ser de interés para la comunidad.

Para los antiguos usuarios de mi antiguo blog, comunicar que, a pesar de publicar los artículos de entrada en geeks.ms, haré crossposting de aquellas de interés para que aquél se mantenga activo.

Para terminar, espero que este blog esté a la altura de sus vecinos y poder ayudar en todo lo posible a la comunidad.

Gracias por vuestro tiempo.

Keep Pushing!