Estoy en la nube: Ya está en el marketplace de Windows Phone 7

ApplicationIcon

Hola a todos!

Desde hoy puedes descargar para tu Windows Phone 7 una aplicación que te mantendrá al día de las novedades de Windows Azure, Office 365 y todo este mundo del Cloud Computing de Microsoft, de la mano de Ibon Landa, uno de los mayores expertos en Azure que podemos encontrar en nuestro país, junto con artículos de Unai Zorrilla y otros compañeros, que podéis encontrar regularmente en www.estoyenlanube.com

screenshot001screenshot002

Puedes descargar la aplicación directamente en el siguiente enlace, espero que te guste!

download from marketplace

Un saludo y Happy Coding!

[EVENTO] Scrum Week Madrid 2011

Hola a todos!

la semana del 4 de abril se llevará a cabo una semana de formación Ágil con grandes ponentes como Rodrigo Corral, Jose Luis Soria, Ibon Landa, Angel Medinilla, Unai Zorrilla y Alejandro Barrera.

Si te interesa aprender de una forma profesional y de primera mano sobre Arquitecturas ágiles, Coaching de equipos ágiles, Scrum, pruebas unitarias, y muchas cosas más no puedes perdertela, un must have en el calendario de formación anual:

http://www.scrumweek.com/proximas-ediciones/scrumweek-madrid-4-8-de-abril-de-2011/

Un saludo y Happy Coding

[BMOS] Barcelona Mobile Open Space 2011

Hola a todos,

Este sábado 19 de marzo de 2011 he tenido la suerte y el gran placer de asistir a un evento organizado por Agile Barcelona y Catdroid  sobre agilismo y tecnologías móviles, con  115 inscritos oficialmente y 75 asistentes finalmente.

En principio pensé que me encontraría en lo que yo llamo “territorio comanche”, puesto que la mayoría de los asistentes son profesionales del desarrollo móvil para Android e Iphone, y yo era en principio el único desarrollador de Windows Phone 7.

El formato open space se basa en la auto organización de los asistentes, los cuales proponen los temas de los que quieren hablar, debatir o exponer, y luego entre todos se eligen por votación las sesiones y se colocan en su horario por importancia:

WP_000068

@vgaltes poniendo orden en el panel jeje

Es sorprendente como se consigue meter a 75 personas que no se conocen casi de nada en una sala, con intereses muy diferentes, incluso en algunos casos intereses contrapuestos o enfrentados, y estos son capaces de organizar una agenda de 24 sesiones, a lo largo de 9 horas de una forma cívica y respetuosa, un aplauso a todos los asistentes de mi parte, sois un ejemplo único para cualquiera.

Las sesiones que pudimos ver fueron de lo más variado, Contratos Ágiles, Introducción al agilismo, tecnología NFC, accesibilidad en aplicaciones móviles,  localización de aplicaciones móviles, monetización de aplicaciones móviles… por mi parte propuse dos charlas, una mesa redonda sobre las tres plataformas presentes: iOS, Android y Windows Phone 7, y un taller práctico de Windows Phone 7, al principio tuve mis serias dudas de que la gente se apuntase a ellas, pero la gente las votó y finalmente, junto con un taller de Android y un taller de Iphone realizamos el taller de Windows Phone 7 y la mesa redonda (antes de los talleres) a modo de introducción.

WP_000071

Taller de Android con @sergiandreplace

 

WP_000072

Taller de iOS con @openinput y @pedromsantos

 

260489005

Taller de Windows Phone 7 con @josueyeray (ese soy yo… )

 

Por mi parte tengo que decir, Android me sorprendió gratamente, Eclipse ha mejorado mucho (aunque aun está lejos de Visual Studio) y funciona bastante bien, aunque nos comentó @sergiandreplace que el emulador fallaba bastante (en eso también ganamos, nuestro emulador va muuy bien). Lamentablemente, aunque me pareció una charla muy interesante, iOS me parece igual que siempre, aunque estábamos viendo la ultima versión de las herramientas de desarrollo (XCode 4.3) me dio la impresión de herramienta complicada y un poco revuelta, eso sin hablar de Objetive-C, creo que Apple se ha quedado en los 80 en cuanto a sus herramientas de desarrollo.

También me sorprendió mucho lo maravillada que se quedo la gente con Visual Studio 2010 y Expression Blend, teniendo en cuenta que la mayoría de los asistentes eran desarrolladores Android e iOS, creo que se sorprendieron de lo bien que funcionan las herramientas de Microsoft para Windows Phone y lo productivas que son. Estos son algunos tweets al respecto durante la charla de Windows Phone 7:

“iOs y Android toca ponerse las pilas q llega WP7 con muchas ganas. Genial demo de @JosueYeray en #bmos”

“Que bien nos ha vendido WP7 @JosueYeray en el #bmos. En la mesa redonda sólo ha convencido esta plataforma y yo programo para Android”

Podéis encontrar todos los tweets del día buscando el hashtag #bmos.

Mientras nosotros nos divertíamos picando Java, Objetive-C y C#, @vgaltes y otros abnegados justicieros del agilismo celebraban una dura sesión sobre contratos ágiles:

WP_000073

Esto es trabajar duro por el agilismo… pobrecitos jeje.

Como no todo en esta vida es agilismo y picar código, también tuvimos un descanso para comer y… seguir debatiendo Sonrisa

cabr

Hay estamos @josueyeray y @vgaltes, haciendo imagen corporativa con nuestros polos de Plain Concepts

 

En definitiva un muy buen evento, donde todos hemos aprendido y donde primaron el respeto y las ganas de conocer, frente a las diferencias y los fanatismos.

Enhorabuena a la organización y a todos los asistentes, espero que pronto podamos coincidir en otro evento.

[WP7] Actualización de Marzo de Cloud Services SDK (Project Hawaii)

image

Hola a todos!

 

El 4 de marzo Microsoft actualizó el SDK de Cloud Services para Windows Phone, si no has oído hablar de él, revisa esta entrada de mi blog para encontrar una introducción a este kit de desarrollo que nos permite aprovechar el potencial de azure desde nuestros teléfonos de forma sencilla.

En esta nueva versión se ha incluido un nuevo sample y documentación para usarlo sobre una de las características más interesantes de Cloud Services: STT (Speech To Text o Reconocimiento de voz) que nos permite usar nuestro dispositivo WP7 como si de una grabadora se tratase para acto seguido enviar el audio a azure y obtener como resultado una transcripción del audio enviado.

Una vez enviado el audio, recibimos varias opciones de transcripción del mismo, para que podamos escoger la que mejor se ajuste a la realidad, en la siguiente imagen le enviamos un “Hello World” y esto son los resultados que obtenemos:

image

Como podemos observar varios resultados coinciden completamente, por lo que podríamos obtener el resultado que es igual un mayor numero de veces y aceptarlo como bueno si quisiésemos realizar este paso sin mostrar opciones al usuario.

Por ahora solo cuenta con un tipo de diccionario de voz: independiente del contexto y en ingles, pero debemos recordar que todavía hablamos de un SDK en pleno desarrollo y no de una versión final.

En el sample incluido en el SDK disponemos de un archivo wav pregrabado que podemos usar para probar que el servicio funciona correctamente. Para que funcione correctamente debemos realizar varios pasos, os dejo un video explicando cada uno de ellos y viendo el sample en acción:

WP7 Speech to Text en acción

No dejéis de descargaros esta nueva versión y jugar con ella (aquí), creo que es uno de los grandes potenciales de WP7 y que en el futuro dará mucho juego a los desarrolladores.

Un saludo a todos y Happy Coding!

[WPF] Localización de aplicaciones

Hola a todos!

Ayer hablando con Jorge Serrano, Lluis Franco, Javier Torrecilla y Eduard Tomàs por twitter surgía la duda de como y cual es la mejor forma de localizar aplicaciones en WPF.

Actualmente existen dos métodos ampliamente usados para localizar nuestra aplicación WPF.

El más extendido se basa en usar archivos de recursos (resx) que contengan los textos en diferentes idiomas y, usando una clase wrapper, mediante un ObjectDataProvider enlazar a estos recursos de forma que cuando el idioma cambie en la cultura de la aplicación, el ObjectDataProvider refresque los bindings de los textos hacia el idioma correcto.

El otro método se basa en el uso de ensamblados satélites. Debemos marcar los objetos que queramos traducir en XAML con el atributo Uid, luego, usando una herramienta llamada BamlTool exportaremos todos estos objetos junto a sus textos a un fichero que podemos editar y traducir para acto seguido, usando la herramienta BamlTool de nuevo generar un ensamblado con nuestros textos traducidos. Repetimos estos pasos por tantos idiomas como deseemos controlar y automáticamente cuando la aplicación detectará el idioma actual y usará el ensamblado apropiado.

Oficialmente, a partir de .NET 3.5 Microsoft recomienda usar el segundo método, los ensamblados satélites, aunque ambos métodos presentan sus más y sus menos.

Mucha gente (la mayoría de hecho) siguen usando el método de archivos de recursos resx, aunque Microsoft se empeña en dejar bien claro que los archivos resx están obsoletos para estos menesteres.

El problema principalmente lo encontramos en que, cada vez que añadamos un control nuevo a nuestra aplicación, con la solución de los archivos de recursos, solo debemos añadir el texto de este control a cada archivo resx en su correspondiente idioma, mientras que con la técnica de bamltool debemos regenerar los ensamblados satélites una y otra vez, lo cual nos obliga a ir a la linea de comandos, ejecutar la herramienta,… además, la herramienta bamltool está actualmente en estado beta, por lo que, aunque Microsoft nos recomienda usarla, la usamos “as is” sin ninguna garantía… lo cual hace que a muchos les tiemble la mano al tener que usarla en entornos de producción, algo totalmente comprensible.

Bueno, aun así, como estos son los dos métodos mayoritariamente aceptados como válidos (supongo que habrá más formas de localizar una app, los caminos del código son infinitos) vamos a ver un ejemplo de cada uno de ellos y que el lector se encargue de elegir por sí mismo el camino más adecuado para su situación.

Usando recursos

Bueno, para empezar, vamos a crear una aplicación WPF nueva con una interface muy sencilla, unos botones (3) y un textblock, algo así:

image

El código XAML necesario es realmente sencillo:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width=".3*"></ColumnDefinition>
        <ColumnDefinition Width=".3*"></ColumnDefinition>
        <ColumnDefinition Width=".3*"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="30"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <TextBlock Grid.ColumnSpan="3" Grid.Row="0"
                HorizontalAlignment="Center"
                VerticalAlignment="Top"
                Text="Prueba de cambio dinámico de idiomas"></TextBlock>
        
    <Button Content="Español" Grid.Row="1" Grid.Column="0" Margin="5"></Button>
    <Button Content="Ingles" Grid.Row="1" Grid.Column="1" Margin="5"></Button>
    <Button Content="Italiano" Grid.Row="1" Grid.Column="2" Margin="5"></Button>
</Grid>

Una vez creado nuestro interface de usuario, el cual tiene los textos Hard coded en el propio XAML algo que no es demasiado elegante, vamos a crear unos archivos de recursos para poder tener nuestra aplicación en español, ingles e italiano, para mantener algo de orden en la solución los agruparemos en una carpeta idiomas y los llamaremos idiomas.resx, idiomas.en.resx e idiomas.it.resx, uno para cada idioma:

image

Una vez creados, es muy importante que entremos en cada archivo de recursos y establezcamos su modificador de acceso (Access Modifier) a public, para poder acceder a las cadenas de texto de los recursos usando nombres fuertemente tipados:

image

Una vez hecho todo esto, vamos a crear en cada archivo unos recursos para el textblock y otro para cada botón. Recuerda, querido lector, que para que todo funcione correctamente en todos los archivos de recursos una cadena debe tener el mismo nombre, aunque cambiemos su valor dependiendo del idioma:

image

Ahora ya tenemos los textos de nuestra aplicación en un archivo de recursos, vamos a crear una clase Wrapper que nos permita acceder a ellos desde un ObjectDataProvider y enlazarnos a el mediante XAML:

public class WrapperIdiomas
{
    private static ObjectDataProvider m_provider;
        
    public WrapperIdiomas()
    {
    }

    //devuelve una instancia nueva de nuestros recursos.
    public idiomas GetResourceInstance()
    {
        return new idiomas();
    }

    //Esta propiedad devuelve el ObjectDataProvider en uso.
    public static ObjectDataProvider ResourceProvider
    {
        get
        {
            if (m_provider == null)
                m_provider = (ObjectDataProvider)App.Current.FindResource("IdiomasRes");
            return m_provider;
        }
    }

    //Este método cambia la cultura aplicada a los recursos y refresca la propiedad ResourceProvider.
    public static void ChangeCulture(CultureInfo culture)
    {
        Properties.Resources.Culture = culture;
        ResourceProvider.Refresh();
    }
}

Esta clase es muy sencilla, se compone de varios métodos que se encargan de refrescar el idioma (cultura) aplicado en la aplicación y devolver los recursos apropiados para la cultura establecida.

Una vez hecho esto, vamos a crear nuestro ObjectDataProvider en el archivo App.Xaml:

Primero debemos referenciar el namespace donde se encuentra nuestro wrapper:

xmlns:idiomas="clr-namespace:Resources.idiomas"

Ahora crearemos el ObjectDataProvider:

<ObjectDataProvider x:Key="IdiomasRes" 
                    ObjectType="{x:Type idiomas:WrapperIdiomas}" 
                    MethodName="GetResourceInstance">
</ObjectDataProvider

Ahora ya podremos enlazar nuestros controles en XAML, usando Databinding, directamente al recurso que deseemos. Es recomendable recompilar el proyecto antes de enlazar en XAML:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width=".3*"></ColumnDefinition>
        <ColumnDefinition Width=".3*"></ColumnDefinition>
        <ColumnDefinition Width=".3*"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="30"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <TextBlock Grid.ColumnSpan="3" Grid.Row="0"
        HorizontalAlignment="Center"
        VerticalAlignment="Top"
        Text="{Binding Texto, Source={StaticResource IdiomasRes}}"></TextBlock>

    <Button Content="{Binding Boton_español, Source={StaticResource IdiomasRes}}" 
            Grid.Row="1" Grid.Column="0" Margin="5" Click="Español_Click"></Button>
    <Button Content="{Binding Boton_ingles, Source={StaticResource IdiomasRes}}" 
            Grid.Row="1" Grid.Column="1" Margin="5" Click="Ingles_Click"></Button>
    <Button Content="{Binding Boton_italiano, Source={StaticResource IdiomasRes}}" 
            Grid.Row="1" Grid.Column="2" Margin="5" Click="Italiano_Click"></Button>
</Grid>

Como podemos ver, ahora ya tenemos una solución mucho más decente, que nos permite reutilizar cadenas y no tener textos escritos por nuestro XAML. Si todo ha ido bien, si abres la vista de diseño, verás los textos en el idioma del sistema operativo (siempre que esté en español, ingles o italiano) ya queda muy poco para terminar, vamos a indicarle a cada botón en el evento click, que cambie la cultura de la aplicación a la que le corresponda y que llame al método ChangeCulture de nuestro wrapper:

private void Español_Click(object sender, RoutedEventArgs e)
{
    Thread.CurrentThread.CurrentUICulture = new CultureInfo("es-ES");
    idiomas.WrapperIdiomas.ChangeCulture(Thread.CurrentThread.CurrentUICulture);
}

private void Ingles_Click(object sender, RoutedEventArgs e)
{
    Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-GB");
    idiomas.WrapperIdiomas.ChangeCulture(Thread.CurrentThread.CurrentUICulture);
}

private void Italiano_Click(object sender, RoutedEventArgs e)
{
    Thread.CurrentThread.CurrentUICulture = new CultureInfo("it-IT");
    idiomas.WrapperIdiomas.ChangeCulture(Thread.CurrentThread.CurrentUICulture);
}

Y con esto, si ejecutamos nuestra aplicación, veremos que por defecto usa el idioma de nuestro  S.O. y podemos cambiar el idioma pulsando cada uno de los botones.

Conclusión

Como os comente al inicio, cada uno de los métodos que podemos usar tiene sus inconvenientes, el gran inconveniente que tiene a mi entender esta aproximación mediante recursos es que no es interoperable entre WP7, Silverlight y WPF, puesto que Silverlight, tanto en su versión web como móvil, carecen del objeto ObjectDataProvider, lo que evita que podamos compartir de forma incondicional este método.

En un próximo artículo veremos como generar ensamblados satélites y traducir nuestras aplicaciones, también veremos como localizar aplicaciones silverlight y Wp7.

Os dejo una demo con código, espero que os guste tanto leer este artículo como a mi escribirlo.

Un gran saludo y Happy Coding!

Windows Phone 7 y WCF

 

Introducción

Windows Phone 7 y Windows Communication Foundation forman un excelente dúo.

Debido a la gran orientación de Windows Phone 7 hacia la nube y a la falta de soporte oficial de bases de datos en el teléfono necesitamos encontrar una forma de almacenar nuestros datos fuera del dispositivo. Para esto, Windows Communication Foundation nos ofrece una plataforma segura, robusta y completa que cubrirá todas nuestras necesidades de comunicación con el exterior.

Dada la extensión y potencia de WCF a veces puede ser un poco complicado el hacer que todo funcione correctamente, con esto en mente creamos este artículo para guiaros por los pasos necesarios para llevar a buen término el uso de WCF con Windows Phone 7.

Creación del servicio

A la hora de crear servicios WCF para ser consumidos desde Windows Phone 7 no debemos tener ninguna consideración especial en cuenta, bastará con crear un servicio WCF standard, desde el menú Archivo > Nuevo > Proyecto (File > New > Project) en Visual Studio 2010 y en la pantalla de nuevo proyecto, seleccionar WCF de la lista de plantillas y WCF Service Application de los proyectos WCF disponibles.

image

 

Configuración del servicio

Una vez creado nuestro servicio WCF podremos desarrollarlo de forma normal, atendiendo a ciertas restricciones de configuración o características no soportadas actualmente por Windows Phone 7, a continuación tenemos una tabla en la que podemos ver una comparación entre el soporte de WCF que nos ofrece Windows Phone 7, y las versiones de escritorio de Silverlight (3 y 4):

Característica Versión

WP7

Silverlight 3

Silverlight 4

Bindings HTTP

X

X

X

Comunicación Duplex

 

X

X

Sindicación Rss

 

X

X

Bindings Custom

 

X

X

DataContract Serialization

X

X

X

Seguridad HTTPS

X*

X

X

JSON

 

X

X

Sockets

 

X

X

Seguridad BasicHttp

X

X

X

Proxy dinámico

 

X

X

* Solo disponible con ciertas entidades certificadoras: http://msdn.microsoft.com/en-us/library/gg521150(v=VS.92).aspx

Como podemos observar, en estos momentos Windows Phone 7 soporta las características básicas de WCF, podemos ver una descripción en profundidad del soporte que tenemos disponible para realizar servicios WCF en este enlace.

Una característica de los binding HTTP que tenemos disponible en WCF para Windows Phone 7 y es muy importante conocer es la sección ReaderQuotas. Esta sección de los binding HTTP indica los límites de tamaño bajo los que se tienen que mantener las peticiones al servicio para ser aceptadas o el tamaño máximo de un array que intentemos enviar. Por defecto el tamaño máximo de array está establecido en 16384, con lo que, por ejemplo, si intentamos enviar un array de bytes que contenga más elementos que 16384 el servicio denegará la petición.

Esta característica está pensada para proteger a nuestro servicio de un posible ataque DOS (Denial of service) que basándose en mensajes complejos intente colapsar los endpoints del servicio WCF. Debido a esto, debemos recordar siempre intentar ajustar los valores de esta sección en la medida de lo posible a los datos que vayamos a recibir, si ajustamos estos parámetros a un valor Max.Int32 estaremos eliminando esta defensa natural que tiene nuestro servicio.

Para configurar esta característica podemos usar la Herramienta de Configuración de Servicio WCF que tenemos disponible en Visual Studio 2010 en el menú Herramientas.

image

Simplemente debemos crear un nuevo binding para nuestro EndPoint y podremos ver la sección ReaderQuotas con los diferentes parámetros que debemos configurar como máximos bytes por lectura o longitud máxima de un array.

Una vez modificados los valores debemos aplicar la configuración a nuestro Endpoint:

image

Y ya solo nos queda guardar el trabajo que hemos realizado y veremos los valores reflejados en el archivo web.config de nuestro servicio:

  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="NewBinding0">
          <readerQuotas
              maxDepth="128"
              maxStringContentLength="1024"
              maxArrayLength="131072"
              maxBytesPerRead="524288"
              maxNameTableCharCount="4">
          </readerQuotas>
        </binding>
      </basicHttpBinding>
    </bindings>
    <services>
      <service name="WcfService.Service1">
        <endpoint
              address="basichttp"
              binding="basicHttpBinding"
              bindingConfiguration="NewBinding0"
              name="basicHTTP"
              contract="WcfService.IService1">
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>

Con esto ya hemos visto cómo crear y configurar nuestro servicio y las restricciones que encontraremos al desarrollarlo para Windows Phone 7, el siguiente paso es conectar nuestra aplicación con nuestro servicio.

Conectando desde Windows Phone 7

El paso necesario para referenciar a un servicio WCF desde nuestra aplicación Windows Phone 7 es realmente simple.

Simplemente haremos click con el botón derecho del ratón sobre nuestro proyecto Windows Phone 7 y seleccionaremos la opción Añadir referencia a servicio (Add Service Reference)

image

 

Si el servicio WCF que deseamos referenciar se encuentra en la misma solución que nuestra aplicación, nos bastará presionar el botón Discover (Descubrir) para que en la lista de servicios aparezca el mismo. Si no es así, deberemos especificar la URL donde se encuentre el servicio WCF y presionar el botón Go (Ir).

Una vez hecho esto, solo tenemos que seleccionar el servicio, indicar el nombre de Namespace que deseamos asignarle y presionar OK para que Visual Studio 2010 se encargue de generar un proxy automáticamente para que tengamos acceso a todos los métodos y clases de nuestro servicio.

Solo tendremos que crear una instancia nueva de la clase que deseemos usar, y podremos acceder a los métodos del servicio, observaremos que el servicio expone métodos asíncronos para todos los métodos que hemos creado puesto que en Windows Phone 7 las peticiones web son asíncronas:

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            ServiceReference1.Service1Client proxy = new ServiceReference1.Service1Client();
            
            proxy.GetDataCompleted += new EventHandler<ServiceReference1.GetDataCompletedEventArgs>(proxy_GetDataCompleted);

            proxy.GetDataAsync(25);
        }

        void proxy_GetDataCompleted(object sender, ServiceReference1.GetDataCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                MessageBox.Show(e.Result.ToString());
            }
        }

Conclusión

Siguiendo los pasos citados en este artículo y leyendo los enlaces que hay a lo largo del texto podremos crear un servicio Windows Communication Foundation optimizado y una aplicación de Windows Phone 7 que haga uso del mismo de forma efectiva y sin problemas.

A continuación tenéis el código fuente completo para descargar, un saludo y Happy Coding!

Programación Asíncrona en Windows Phone 7

Hola a todos!

Una parte muy importante de la experiencia de usuario de nuestra aplicación móvil es la fluidez y rapidez con la que esta responde al usuario, todos hemos usado aplicaciones que ante cierta acción se quedan congeladas durante un periodo de tiempo antes de volver a responder, lo primero que pensamos es que la aplicación se ha bloqueado y la solución por la que optamos suele ser reiniciarla, aunque esperemos y la aplicación vuelva a ser operativa nuestra impresión hacia la usabilidad de la misma suele ser negativa. Además de esto, en Windows Phone 7 uno de los requerimientos para que nuestro desarrollo supere la aceptación en el marketplace es que la interface de usuario (UI) nunca se “congele”, siempre responda al usuario.

Para llevar a cabo esto, podemos hacer uso de distintos mecanismos de programación asíncrona incluidos en el framework de .NET 4, en esta ocasión vamos a ver como usar la clase BackgroundWorker para obtener de forma sencilla ejecución asíncrona en nuestra aplicación.

Hilos en Windows Phone 7

Toda aplicación Silverlight para WP7 se compone por defecto de dos Hilos:

  • Hilo de Interface de usuario: Es el hilo principal de nuestra aplicación, se encarga de manejar la entrada de usuario, procesar los objetos creados en XAML y ejecutar el resto de nuestro código.
  • Hilo de Composición: Se encarga de manejar tareas que normalmente serían responsabilidad del Hilo de UI, mejorando el rendimiento de las aplicaciones. Por ejemplo este hilo se encarga de procesar, combinar texturas gráficas y enviarlas a la GPU del dispositivo para que las dibuje, también se encarga de manejar las animaciones creadas con Storyboards, enviándolas automáticamente a la GPU y liberando así al hilo principal. Toda transformación realizada con los siguientes elementos se manejará en el hilo de composición:

Sin embargo el hilo de composición tiene limitaciones que pueden hacer que nuestra transformación pase a ejecutarse en el Hilo de UI, con el claro detrimento de rendimiento que experimentaríamos como consecuencia, para evitarlo en la medida de lo posible debemos tener en cuenta estos puntos:

  • Si para la Opacity usamos una máscara de opacidad, se procesará en el hilo de UI.
  • Si queremos hacer Clip de un área no rectangular, se procesará en el hilo de UI.
  • Si establecemos un ScaleTransform mayor al 50% del tamaño, se procesará en el hilo de UI.

Es muy importante que tengamos estos simples puntos en mente e intentemos evitarlos en la medida de lo posible, cada milisegundo ganado en el Hilo de Composición nos aportará mayor fluidez en nuestra interface de usuario.

BackgroundWorker

La clase BackgroundWorker es el método más sencillo para ejecutar código en un nuevo hilo. Tiene incluida funcionalidad para cancelar el procesamiento asíncrono, notificar el progreso, ejecutar código en el nuevo hilo y notificar la finalización de la tarea. Se encuentra definida en el namespace System.ComponentModel.

Es muy sencillo trabajar con esta clase, básicamente, debemos crear un manejador para el evento DoWork, este manejador es el que se ejecutará en el nuevo hilo dedicado, disponemos del evento ProgressChanged, que podemos manejar y lanzar durante el progreso de nuestra operación con el método ReportProgress. Una vez que la ejecución ha terminado se lanza el evento RunWorkerCompleted que de nuevo se ejecuta en nuestro hilo principal, en el que podemos comprobar si el proceso termino con errores, si se cancelo o si termino correctamente.

Durante la ejecución de nuestro código en el evento DoWork (asíncrono) desde el hilo principal podemos llamar al método CancelAsync, haciendo esto, si comprobamos la propiedad CancellationPending desde nuestro código asíncrono, obtendremos su valor a true, lo que siginifica que el usuario ha solicitado la cancelación, simplemente deberemos establecer a True la propiedad Cancel de DoWorkEventArgs y salir del método lo antes posible, momento en el que se lanzará el evento RunWorkerCompleted y, comprobando la propiedad Cancelled de RunWorkerCompletedEventArgs obtendremos true y podremos responder de forma adecuada.

Vamos a ver esto pasos con código para que quede más claro, tengo un pequeño ejemplo, una aplicación que cada 1,5 segundos añade un item a un listbox indicando el progreso de la tarea, usando para todo ello la clase BackgroundWorker:

Primero tenemos que inicializar una nueva instancia, indicandole que soportamos notificar progreso y cancelación (de lo contrario, al intentar cancelar o informar del progreso recibiremos una excepción de tipo InvalidOperationException), también vamos a crear los manejadores de eventos para DoWork, ProgressChanged y RunWorkerCompleted:

BackgroundWorker worker = new BackgroundWorker();

worker.WorkerSupportsCancellation = true;
worker.WorkerReportsProgress = true;

worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

 

A continuación incorporamos el código que deseemos ejecutar en el hilo asíncrono al evento DoWork (CUIDADO! este código no puede acceder directamente a la interface de usuario o recibiremos una excepción de Cross Threading inválido):

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i = 1; i < 10; i++)
    {
        Thread.Sleep(1500);
        worker.ReportProgress(i*10);
        if (worker.CancellationPending)
        {
            e.Cancel = true;
            return;
        }
    }
}

 

¿Y que pasa si queremos actualizar un control desde este código? Bueno, para esto WPF/Silverlight y por supuesto Windows Phone 7 ponen a nuestra disposición el Dispatcher, que básicamente nos sirve para indicar a un control que deseamos que ejecute código por nosotros, en el ejemplo anterior podriamos usar el Dispatcher de la ventana para que añada un Item a nuestro Listbox, en vez de usar el método ReportProgress:

this.Dispatcher.BeginInvoke((Action)delegate()
    {
        listCurrentOP.Items.Add("Elemento añadido con dispatcher.");
    });

 

Simplemente estamos indicanto el código que queremos ejecutar, y la ventana se encargará de ejecutarlo por nosotros, además, al usar BeginInvoke (en Windows Phone 7 solo está disponible este método) la ejecución continua automáticamente sin esperar a que se ejecute el código indicado al Dispatcher, por lo que continuamos nuestra filosofía de que nuestra aplicación siempre sea “usable”.

Cada vez que llamamos al método ReportProgress pasandole un valor numérico se lanza el evento ProgressChanged en el que, por ejemplo, podemos actualizar un control progressbar que muestre al usuario el progreso de la tarea, ten en cuenta que este evento SI se ejecuta en el hilo principal,  por lo que podrás acceder a los controles sin ningún problema de Cross Threading:

void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    listCurrentOP.Items.Add(string.Format("Progreso: {0}.", e.ProgressPercentage));
}

 

Por último, una vez que el evento DoWork a terminado, se lanza el evento RunWorkerCompleted, donde podremos controlar posibles errores, cancelaciones o que todo ha funcionado correctamente:

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    StartWorker.IsEnabled = true;
    if (e.Cancelled)
    {
        listCurrentOP.Items.Add("Cancelado por el usuario.");
        return;
    }
    if (e.Error != null)
    {
        listCurrentOP.Items.Add("Error.");
        return;
    }

    listCurrentOP.Items.Add("Completado.");
}

 

Y listo! ya tenemos ejecución asíncrona en nuestras operaciones más pesadas, con cancelación, notificación de progreso y notificación de terminación, además el uso de la clase BackgroundWorker no es nada complicado.

 Os dejo para que podáis descargar el proyecto usado en este ejemplo, en Visual Studio 2010 para Windows Phone 7.

Un saludo a todos, gracias por leerme y Happy Coding!

[WP7] Actualización del kit de desarrollo para Windows Phone 7

winphone

Hola a todos!

Ya tenemos con nosotros una nueva actualización de las herramientas de desarrollo de Windows Phone 7, vamos a dar un vistazo a que nos ofrecen.

Lo primero… para todos los que esperábamos una sorpresa por parte de Microsoft en forma de nuevas APIs: Hay que seguir esperando, por el momento este update no nos ofrece nuevas APIs como la tan deseada captura de video en vivo y que, a mi parecer, tanta falta le hace a la plataforma, quizás incluso más falta que la multitarea.

¿Que nos trae de nuevo este emulador entonces?

Básicamente, este update nos ofrece Copy & Paste en nuestro emulador (por fin!), aunque con restricciones, solo se podrá copiar texto desde los controles TextBox, PasswordBox y WebBrowser, por lo que si queremos mostrar un texto susceptible de ser copiado por el usuario deberemos usar alguno de estos controles. De forma ideal, los desarrolladores deberíamos tener acceso a un API que nos permitiese meter texto en el portapapeles, pero por ahora, no existe tal API, por lo que deberemos adaptarnos a estos controles para usar el copy & paste.

El emulador en si mismo es mucho más rápido, se nota sobre todo en un fresh start, cuando arrancamos el emulador desde cero, tarda mucho menos tiempo en cargar y hacer el deploy desde Visual Studio.

Por otro lado, hasta ahora teníamos un problema a la hora de depurar aplicaciones que hiciesen uso de la radio u otras APIs multimedia, al intentar depurar estas aplicaciones con el Zune ejecutándose obteníamos una excepción de seguridad, pero si cerrábamos Zune no podíamos depurar nuestra aplicación desde Visual Studio. En este update se incluye una nueva herramienta llamada Windows Phone Connect que nos permitirá conectar a nuestro dispositivo desde Visual Studio con el software Zune cerrado y podremos depurar nuestras aplicaciones multimedia sin contratiempo. Esta herramienta la podemos encontrar en ProgramFilesMicrosoft SDKsWindows Phonev7.0ToolsWPConnect. Podéis encontrar una descripción y más detalles de su uso aquí

También tenemos una nueva herramienta llamada Capability Detection Tool  ubicada en ProgramFilesMicrosoft SDKsWindows Phonev7.0ToolsCapDetect que nos permitirá detectar las capacidades del teléfono que requiere nuestra aplicación y reemplazar las creadas por defecto. Más información aquí

Es importante saber que las aplicaciones existentes compilan correctamente sin necesidad de realizar ningún cambio y que la funcionalidad de copy & paste es nativa del sistema por lo que no tenemos que implementar nada nuevo en nuestra aplicación para hacer uso de ella, sin embargo si que nos avisan desde Microsoft que si un usuario intenta copiar un texto en un control dentro de un Pivot o Panorama, puede mover la pantalla sin quererlo, esto está solucionado en este update, pero si que nos exige recompilar y subir una actualización de nuestra aplicación a Marketplace para subsanar este comportamiento anómalo.

Por último he grabado un video del emulador arrancando desde cero y usando la característica de Copy & paste para que juzguéis por vosotros mismos si realmente ha mejorado en velocidad, espero que os guste.

Un vistazo rápido al emulador nuevo de WP7 & copiar/pegar

 

Un saludo y Happy Coding!

[Materiales] WebCast Extiende tu aplicación con Managed Extensibility Framework (MEF)

Hola a todos!

El pasado martes 1 de Febrero tuve el gran placer de unirme con la gente de SecondNug para hablar un rato sobre MEF, enseñar las posibilidades de extensión que nos ofrece y lo sencillo que resulta implantarlo en nuestras aplicaciones.

Para los que asististeis y para los que no pudisteis asistir ya está disponible tanto la grabación del evento como los materiales (ppt y demo vs2010) para descargar desde la web de SecondNug:

http://www.secondnug.com/EventosDesarrollo/tabid/57/Default.aspx

Muchas gracias a la gente de SecondNug por la ayuda para realizar el evento y la colaboración durante el mismo, ha sido una experiencia muy buena que espero repetir 🙂 y muchas gracias a todos los que asististeis por estar allí

Un saludo y Happy Coding!

Windows Phone 7: Primer Vistazo a Cloud Service SDK (Project Hawaii)

Hola a todos!

Ayer Microsoft Research Labs liberó la versión 0.5 del Cloud Service SDK para Windows Phone 7. Este SDK está pensado como una forma de trabajar de manera eficiente desde Windows Phone 7 con Azure y se enmarca dentro del proyecto Hawaii, cuyo objetivo era investigar las mejores formas de extender y complementar las aplicaciones móviles con la nube.

Podéis encontrar más información aquí y descargar el SDK en esta página.

 

Primeros pasos

Una vez que hayamos instalado el Cloud Service SDK tendremos una serie de archivos y soluciones a nuestra disposición en la ruta users<usuario>DocumentsMicrosoft ResearchHawaii SDK.5

En esta ruta podemos encontrar los dos primeros servicios que el proyecto Hawaii ha liberado para Windows Phone 7: Relay Service y Rendezvous Service.

Relay Service usa la nube para crear un endpoint que las aplicaciones pueden usar para comunicarse entre dispositivos, rodeando, de esta forma, la restricción en las conexiones móviles que existe al no disponer de una IP Pública fija, pudiendo crear aplicaciones que se comuniquen entre dispositivos de manera mucho más sencilla.

Rendezvous Service mapea nombres Human-friendly a endpoints en la nube para que sea más sencillo descubrir y conectar a estos endpoints del Relay Service.

Ojeando el nuevo juguete

Si abrimos la solución RendezvousTestClient en el directorio Samples veremos la siguiente estructura de proyecto:

image

En el proyecto RendezvousClientLibrary tenemos todo el código para conectarnos al servicio Rendezvous en Azure, la mayor parte del trabajo se realiza en la clase NameRegistration que nos permite realizar búsquedas de endpoints a partir de un nombre, en especial es interesante echar una ojeada al método Lookup:

public bool Lookup()
{
// -
// Generate name lookup request.
// -
string remainder = "Name/" + this.name;
Uri uri = new Uri(RendezvousService.ServiceUri, remainder);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "GET";
            
// -
// Get the rendezvous service's response.
// -
HttpWebResponse response = null;
HttpStatusCode status;
XmlReader reader = null;
try
{
#if SILVERLIGHT
    response = FakeSynchronous.FakeGetResponse(request);
#else
    response = (HttpWebResponse)request.GetResponse();
#endif
    status = response.StatusCode;

    // -
    // Read the returned information.
    // -
    reader = XmlReader.Create(response.GetResponseStream());
    while (reader.Read())
    {
        if (reader.NodeType == XmlNodeType.Element)
        {
            if (reader.Name.Equals(
                "TransceiverId",
                StringComparison.OrdinalIgnoreCase))
            {
                string temp = reader.ReadElementContentAsString();
                this.registrationId = Convert.ToUInt64(temp, 16);
                this.valid = true;
            }
        }
    }
}
catch
{
    return this.valid;
}
finally
{
    if (reader != null)
    {
        reader.Close();
    }

    if (response != null)
    {
        response.Close();
    }
}

return this.valid;
}

En este método podemos ver la sencillez del concepto detrás del servicio, hacemos un webrequest al servicio Rendezvous, nos devuelve un XML que procesamos y que nos informa del registrationID del endpoint que hemos pedido por nombre (si lo ha encontrado).

Por otro lado, si abrimos el proyecto RelayTestClient encontraremos la siguiente estructura:

image

En el proyecto RelayClientLibrary tenemos la clase Endpoint, encargada de gestionar (crear, eliminar y mantener) los endpoints en la nube, podemos ver el constructor de la clase que se encarga de crear el endpoint con un nombre asociado:

        public Endpoint(
            string deviceId,
            string name,
            TimeSpan ttl)
        {
            this.valid = false;
            bool gotRegistrationId = false;
            bool gotSecret = false;

            // -
            // Generate endpoint creation request.
            // -
            string remainder =
                "Endpoint?DeviceId=" + Uri.EscapeUriString(deviceId) +
                "&Name=" + Uri.EscapeUriString(name) +
                "&TTL=" + Uri.EscapeUriString(ttl.TotalSeconds.ToString());
            Uri uri = new Uri(RelayService.ServiceUri, remainder);
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
            request.Method = "POST";
#if !SILVERLIGHT
            request.ContentLength = 0;
#endif

            // -
            // Get the relay service's response.
            // Note that GetRequestStream will initiate the HTTP request and
            // may throw an exception if the request fails.
            // -
            HttpWebResponse response = null;
            HttpStatusCode status;
            XmlReader reader = null;
            try
            {
#if SILVERLIGHT
                response = FakeSynchronous.FakeGetResponse(request);
#else
                request.GetRequestStream().Close();
                response = (HttpWebResponse)request.GetResponse();
#endif
                status = response.StatusCode;

                // -
                // Read the returned information.
                // -
                reader = XmlReader.Create(response.GetResponseStream());
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element)
                    {
                        if (reader.Name.Equals(
                            "Endpoint",
                            StringComparison.OrdinalIgnoreCase))
                        {
                            while (reader.MoveToNextAttribute())
                            {
                                if (reader.Name.Equals(
                                    "TransceiverId",
                                    StringComparison.OrdinalIgnoreCase))
                                {
                                    this.registrationId = Convert.ToUInt64(
                                        reader.Value, 16);
                                    gotRegistrationId = true;
                                }
                            }
                        }
                        else if (reader.Name.Equals(
                            "Secret",
                            StringComparison.OrdinalIgnoreCase))
                        {
                            string temp = reader.ReadElementContentAsString();
                            this.secret = Convert.ToUInt32(temp, 16);
                            gotSecret = true;
                        }
                    }
                }
            }
            catch
            {
                return;
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }

                if (response != null)
                {
                    response.Close();
                }
            }

            this.valid = (status == HttpStatusCode.Created) &&
                gotRegistrationId && gotSecret;
        }

Igual que anteriormente con el servicio Rendezvous y el método lookup, este constructor nos ofrece una implementación muy sencilla y comprensible del servicio RelayService, de nuevo enviamos una petición webrequest (POST) con 3 parámetros que identificarán nuestro endpoint, un id de dispositivo, un nombre para asignarle y el time to live para el servicio.

En respuesta a esto obtenemos un XML con el ID del endpoint creado y el código secreto para autentificar los mensajes enviados/recibidos por el endpoint.

¿Que más va a llegar?

Realmente tiene muy buena pinta el Cloud Service SDK, aunque he tenido pocas horas para jugar con el, ya se me están ocurriendo muchas aplicaciones que se podrían beneficiar de estos servicios. Pero lo mejor de todo es que esto solo es la punta del iceberg, Microsoft Research amenaza con una nueva release en febrero que nos traiga servicios tan útiles como reconocimiento de OCR en la nube (nosotros subimos una imagen y ellos nos devuelven el texto) o servicios Speech to Text (subimos un archivo de audio y nos devuelven texto de la voz).

Conclusión

Vamos a tener que estar muy atentos a Cloud Service SDK, en los próximos meses podemos ver una explosión de aplicaciones en Windows Phone 7 que hagan uso de estos servicios y de más cosas que nos tendrán reservadas los chicos de Project Hawaii.

Un gran saludo y Happy Coding!