[Universal App] Usando las APIs Credential Locker

Introducción

En determinadas ocasiones, nuestras aplicaciones requieren seguridad o
personalización por usuario. En estos casos son típicos problemas como,
como almacenar usuario y contraseña, encriptar la información,
gestionar múltiples dispositivos, etc.

Era un proceso “habitual” pero que requiere tener en cuentas
bastantes aspectos. Ahora con la llegada de las APIs Credential Locker
disponibles en Windows.Security.Credentials, todo el proceso es mucho más simple.

En este artículo vamos a conocer las APIs de Credential Locker
utilizñandolas en un ejemplo real donde veremos como almacenar,
recuperar y eliminar claves.

¿Te apuntas?

¿Credential Locker?

El almacén de credenciales nos permite almacenar y administrar de forma segura
contraseñas de usuarios de una aplicación o servicio específico de modo
que por un lado, los datos almacenados de una aplicación se transfieren
automáticamente a los otros dispositivos de confianza del usuario,
simplificando el proceso de autenticación tanto a los usuarios como a
nosotros, y por otro lado, no es posible desde una aplicación o servicio
acceder a los credenciales asociados con otra aplicación o servicio.

Primeros pasos

Comenzamos creando un nuevo proyecto:

Añadimos las carpetas Views, ViewModels y Services además de las clases base necesarias para implementar el patrón MVVM de la misma forma que vimos en este artículo.

Nuestro objetivo sera muy sencillo. Nuestra aplicación de ejemplo
pedirá fuente, usuario y contraseña permitiéndo con tres sencillos
botones, añadir, recuperar y eliminar credenciales utilizando la API
Credential Locker.

Comenzamos definiendo la interfaz de usuario:

<StackPanel Margin="12">
     <StackPanel Orientation="Vertical">
          <TextBox Header="Source" PlaceholderText="https://facebook.com" />
          <TextBox Header="User" PlaceholderText="user@mail.com" />
          <PasswordBox Header="Password" PlaceholderText="1234abcd" />
     </StackPanel>
     <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
          <Button Content="Guardar" />
          <Button Content="Recuperar" Margin="12, 0" />
          <Button Content="Borrar" />
     </StackPanel>
</StackPanel>
Muy simple. Permitimos obtener la información de seguridad requerida y contamos con tres botones de acción. En la viewmodel correspondiente contaremos con propiedades para obtener la información escrita en cada una de las cajas de texto:
// Variables
private string _source;
private string _user;
private string _password;
private string _info;
 
public string Source
{
     get { return _source; }
     set { _source = value; }
}
 
public string User
{
     get { return _user; }
     set { _user = value; }
}
 
public string Password
{
     get { return _password; }
     set { _password = value; }
}
 
public string Info
{
     get { return _info; }
     set
     {
          _info = value;
          RaisePropertyChanged("Info");
     }
}
Y cada botón, ejecutará un comando en la viewmodel:
// Commands
private ICommand _saveCommand;
private ICommand _readCommand;
private ICommand _deleteCommand;
 
public ICommand SaveCommand
{
     get { return _saveCommand = _saveCommand ?? new DelegateCommand(SaveCommandDelegate); }
}
 
public ICommand ReadCommand
{
     get { return _readCommand = _readCommand ?? new DelegateCommand(ReadCommandDelegate); }
}
 
public ICommand DeleteCommand
{
     get { return _deleteCommand = _deleteCommand ?? new DelegateCommand(DeleteCommandDelegate); }
}
 
public void SaveCommandDelegate()
{
 
}
 
public void ReadCommandDelegate()
{
 
}
 
public void DeleteCommandDelegate()
{
 
}
De modo que nuestra interfaz bindeada a las propiedades y comandos correspondientes quedara como podemos ver a continuación:
<StackPanel Margin="12">
     <StackPanel Orientation="Vertical">
          <TextBox Text="{Binding Source, Mode=TwoWay}" Header="Source" PlaceholderText="https://facebook.com" />
          <TextBox Text="{Binding User, Mode=TwoWay}" Header="User" PlaceholderText="user@mail.com" />
          <PasswordBox Password="{Binding Password, Mode=TwoWay}" Header="Password" PlaceholderText="1234abcd" />
     </StackPanel>
     <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
          <Button Content="Guardar" Command="{Binding SaveCommand}" />
          <Button Content="Recuperar" Margin="12, 0" Command="{Binding ReadCommand}" />
          <Button Content="Borrar" Command="{Binding DeleteCommand}" />
     </StackPanel>
     <ScrollViewer>
          <TextBlock Text="{Binding Info}"/>
     </ScrollViewer>
</StackPanel>
Hasta aqui, la interfaz y estructura básica de nuestro ejemplo.

Continuamos centrándonos en la parte importante, la gestión de credenciales.

Gestión de credenciales

Para realizar la gestión de credenciales utilizaremos las APIs Credential Locker disponibles en Windows.Security.Credentials. Vamos a crear un servicio con la siguiente definición:

public interface IPasswordVaultService
{
     void Save(string resource, string userName, string password);
 
     PasswordCredential Read(string resource, string userName);
 
     IReadOnlyList<PasswordCredential> GetAll();
 
     void Delete(string resource, string userName);
}

NOTA: El servicio será inyectado por Ioc en nuestra viewmodel.

El servicio contará con cuatro métodos:

  • Save: Nos permitirá guardar credenciales.
  • Read: Nos permitirá recuperar un credencial concreto.
  • GetAll: Recupera todos los credenciales que tengamos almacenados en el Credential Locker.
  • Delete: Eliminará un credencial concreto almacenado previamente.

Nos centramos a continuación en la implementación de cada método. Comenzamos por el método Save:

public void Save(string resource, string userName, string password)
{
     PasswordVault vault = new PasswordVault();
     PasswordCredential cred = new PasswordCredential(resource, userName, password);
     vault.Add(cred);
}

Analicemos el código superior. Primero, obtenemos una referencia al Credential Locker usando on objeto de tipo PasswordVault definido en el namespace Windows.Security.Credentials. Continuamos creando un objeto de tipo PasswordCredential
que representará el credencial a almacenar con la referencia a nuestra
Aplicación o el tipo de Login utilizado además de los credenciales en
si, usuario y contraseña. Añadiremos el credencial creado al almacén de
credenciales utilizando el método PasswordVault.Add.

Continuamos con el método Read:

public PasswordCredential Read(string resource, string userName)
{
     PasswordVault vault = new PasswordVault();
 
     return vault.Retrieve(resource, userName);
}

Contamos con una gran variedad de opciones para recuperar
credenciales del almacén. En el código de la parte superior utilizamos
la forma más simple posible. Contando con el nombre de la App o tipo de
Login además del nombre de usuario, podemos recuperar la información
utilizando el método PasswordVault.Retrieve.

En el método GetAll utilizamos el método PasswordVault.RetrieveAll  para recuperar todos los credenciales almacenados en la Aplicación:

public IReadOnlyList<PasswordCredential> GetAll()
{
     PasswordVault vault = new PasswordVault();
 
     return vault.RetrieveAll();
}

Además de las dos formas utilizadas contamos con otras opciones para recuperar credenciales:

Por último, nos centramos en el método Delete, que como podemos imaginar se encargará de eliminar un credencial en concreto:

public void Delete(string resource, string userName)
{
     PasswordVault vault = new PasswordVault();
     PasswordCredential cred = vault.Retrieve(resource, userName);
     vault.Remove(cred);
}

De nuevo, es un proceso muy sencillo que podemos hacer con pocas
líneas. Accedemos de nuevo al almacén de credenciales mediante un objeto
de tipo PasswordVault y utilizamos el método PasswordVault.Remove  para eliminar el credencial almacenado pasado como parámetro.

Con nuestro servicio para gestionar el almacén de credenciales
preparado, solo nos falta definir la acción de cada comando. Al guardar
el credencial:

public void SaveCommandDelegate()
{
     if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(User) || string.IsNullOrEmpty(Password))
     {
          return;
     }
 
     try
     {
          _passwordVaultService.Save(Source, User, Password);
          Info += string.Format("Datos guardatos. Resource: {0}, User: {1}, Password: {2}",
          Source, User, Password)
     }
     catch(Exception ex)
     {
          Info += ex.Message;
     }
}

Sencillo, verificamos que los datos que definen el credencial son válidos y en caso afirmativo utilizamos el método Save de nuestro servicio PasswordVaultService. Para recuperar un credencial:

public void ReadCommandDelegate()
{
     if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(User))
     {
          Info += "La fuente y el usuario son obligatorios.";
          return;
     }
 
     try
     {
          var cred = _passwordVaultService.Read(Source, User);
          Info += string.Format("Datos obtenidos con éxito. Resource: {0}, User: {1}, Password: {2}",
          cred.Resource, cred.UserName, cred.Password);
     }
     catch (Exception ex)
     {
          Info += ex.Message;
     }
}

Utilizaremos tras validar la información, el método Read de nuestro servicio. Y por último, en el comando para eliminar credenciales:

public void DeleteCommandDelegate()
{
     if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(User))
     {
          Info += "La fuente y el usuario son obligatorios.";
           return;
     }
 
     try
     {
          _passwordVaultService.Delete(Source, User);
          Info += string.Format("Datos eliminados con éxito. Resource: {0}, User: {1}, Password: {2}",
          Source, User, Password);
     }
     catch (Exception ex)
     {
          Info += ex.Message;
     }
}

Utilizamos el método Delete del servicio.

Podéis descargar el ejemplo realizado a continuación:

Buenas prácticas

  • El almacén de credenciales esta pensado para facilitar la tarea de
    la gestión de la seguridad en nuestras aplicaciones. No se recomienda su
    uso para almacenar grandes cantidades de información. Contamos con
    otras APIs válidas y más adecuadas para esta necesidad.
  • Debemos controlar el ciclo de almacenamiento de credenciales en el
    Password Vault correctamente. No almacenar información hasta haber sido
    autenticado correctamente y haber marcado el usuario que desea recordar
    la información.

Conclusiones

En aplicaciones universales, es decir, tanto en aplicaciones Windows
Phone como en aplicaciones Windows Store, contamos con una API,
disponible bajo el namespace Windows.Security.Credentials llamada Credential Locker
que nos permite gestionar credenciales de usuario con suma facilidad.
La gran ventaja de utilizar la API es que nos almacena la información en
un almacén seguro, la información es encriptada al ser almacenada. Además, otra de las grandes ventajas de utilizar la API es el roaming de los credenciales entre dispositivos de confianza bajo la misma cuenta Microsoft.

Más información

[Windows Phone 8.1] Capturando la pantalla utilizando la API MediaCapture

Introducción

Entre la enorme cantidad de nuevas APIs, controles y herramientas
disponibles con la llegada de Windows Phone 8.1, desde un principio
llamo mucho la atención las nuevas APIs disponibles para grabar en video o tomar capturas de la actividad de la pantalla. Esta nueva característica la tenemos disponible dentro del namespace Windows.Media.Capture y sera nuestro centro de atención en este artículo.

¿Te apuntas?

Primeros pasos

Comenzamos creando un nuevo proyecto:

Añadimos las carpetas Views, ViewModels y Services además de las clases base necesarias para implementar el patrón MVVM de la misma forma que vimos en este artículo.

Nuestro objetivo sera muy sencillo. Nuestra aplicación de ejemplo
contará con un botón para comenzar a grabar lo que ocurre en pantalla y
otro para detener la grabación. Tras terminar la grabación podemos ver
el video resultante.

Antes de comenzar, vamos a añadir la Webcam como capacidad en el archivo Package.manifiest:

Manos a la obra!

Tomar capturas de pantalla de la aplicación e incluso videos es una
funcionalidad fantástica para segun que tipo de aplicaciones y sobretodo
en juegos. En nuestro ejemplo, debíamos contar con “algo” interesante que grabar. Para ello, vamos a añadir un elipse con una animacion Easing de modo que otorgemos el efecto de una bola cayendo y rebotando.

Para gestionar la animación vamos a utilizar el SDK de Behaviors incluido dentro de las extensiones:

Nos centramos en la vista principal, MainView.xaml. Añadimos la elipse:

<Ellipse x:Name="Ball" Height="75" Width="75" Fill="Red" RenderTransformOrigin="0.5,0.5">
     <Ellipse.RenderTransform>
          <TranslateTransform/>
     </Ellipse.RenderTransform>
     <interactivity:Interaction.Behaviors>
          <core:EventTriggerBehavior EventName="Loaded">
               <media:ControlStoryboardAction ControlStoryboardOption="Play" Storyboard="{StaticResource MyStoryboard}"/>
          </core:EventTriggerBehavior>
     </interactivity:Interaction.Behaviors>
</Ellipse>

Al cargar lanzaremos una animacion llamada MyStoryBoard que tenemos definida en los recursos de la página:

<Storyboard x:Name="MyStoryboard">
    <DoubleAnimation From="0" To="250" Duration="00:00:10"
                     Storyboard.TargetName="Ball"
                     Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)">
         <DoubleAnimation.EasingFunction>
              <BounceEase Bounces="40" EasingMode="EaseOut"
                          Bounciness="1.2" />
         </DoubleAnimation.EasingFunction>
     </DoubleAnimation>
</Storyboard>

De este modo, al lanzar la aplicación se lanzará la animación con el siguiente resultado:

Ya tenemos listo el elemento visual a grabar. Necesitamos dos botones en
nuetra aplicación. Uno para grabar la pantalla y otro que permita ver
el resultado:

<Page.BottomAppBar>
     <CommandBar>
          <AppBarButton />
          <AppBarButton />
     </CommandBar>
</Page.BottomAppBar>

Creamos una CommandBar y añadimos los botones. El
primer botón nos permitirá comenzar y detener la grabación del video. El
segundo nos permitirá ver el video resultante. Para poder conseguir
este resultado, en la viewmodel necesitaremos una propiedad
bool que nos indique si se esta grabando el video o no, para permitir
comenzar o detener la grabación y otra propiedad bool que nos indique si
ya hay un video grabado:

private bool _recording;
private bool _result;
 
public bool Recording
{
     get { return _recording; }
     set
     {
          _recording = value;
          RaisePropertyChanged("Recording");
     }
}
 
public bool Result
{
     get { return _result; }
     set
     {
          _result = value;
          RaisePropertyChanged("Result");
     }
}

El segundo botón lo mostraremos cuando la propiedad Result sea cierta, necesitaremos un Converter para convertir la propiedad bool a Visibility:

public class BoolToVisibilityConverter : IValueConverter
{
     public object Convert(object value, Type targetType, object parameter, string language)
     {
          if (value is bool)
               return ((bool) value) ? Visibility.Visible : Visibility.Collapsed;
 
          return Visibility.Collapsed;
     }
 
     public object ConvertBack(object value, Type targetType, object parameter, string language)
     {
          return null;
     }
}

El primer botón nos permite controlar dos estados diferentes:

  • Comenzar a grabar.
  • Detener una grabación.

Si estamos grabando o no nos lo indica la propiedad Recording, necesitaremos dos converters para obtener el Label y el Icon del AppBarButton segun el valor de la propiedad:

public class RecordStateToIconElementConverter : IValueConverter
{
     public object Convert(object value, Type targetType, object parameter, string language)
     {
            var recording = value as bool?;
 
            if (recording != null)
                return recording == true ? new SymbolIcon(Symbol.Stop) : new SymbolIcon(Symbol.Play);
            return new SymbolIcon(Symbol.Stop);
     }
 
     public object ConvertBack(object value, Type targetType, object parameter, string language)
     {
            return null;
     }
}

Cada botón realizará una acción, en la viewmodel, la ejecución de un comando:

private ICommand _recordCommand;
private ICommand _resultCommand;
 
public ICommand RecordCommand
{
     get { return _recordCommand = _recordCommand ?? new DelegateCommandAsync(RecordCommandDelegate); }
}
 
public ICommand ResultCommand
{
     get { return _resultCommand = _resultCommand ?? new DelegateCommand(ResultCommandDelegate); }
}
 
public async Task RecordCommandDelegate()
{   
 
}
 
public void ResultCommandDelegate()
{
 
}

De modo que nuestros dos botones en la CommandBar quedaran:

<AppBarButton
     Label="{Binding Recording, Converter={StaticResource RecordStateToStringConverter}}"
     Icon="{Binding Recording, Converter={StaticResource RecordStateToIconElementConverter}}"
     Command="{Binding RecordCommand}" />
<AppBarButton
     Visibility="{Binding Result, Converter={StaticResource BoolToVisibilityConverter}}"
     Label="Result"
     Icon="Forward"
     Command="{Binding ResultCommand}" />

API Windows.Media.Capture

Llegamos a la parte fundamental del ejemplo y del artículo, el uso de las APIs disponibles en Windows.Media.Capture.
Crearemos un servicio sencillo que nos permita grabar con facilidad lo
que ocurre en la pantalla de nuestro dispositivo. El servicio lo
llamaremos ScreenRecorederService y su definición sera la siguiente:

public interface IScreenRecorderService
{
     ScreenRecorderService.RecordingStatus Status { get; }
     Task Start(string recordName);
     void Stop();
}

Como podemos ver contamos con:

  • Una propieddad Status. Nos permitirá consultar en
    todo momento si el servicio esta grabando la pantalla, esta detenido, ha
    terminado la grabación con éxito o por el contrario ha ocurrido algun
    error.
  • Un evento Start que recibirá como parámetro el
    nombre del video resultante de la grabación. Este evento se encarga de
    comenzar la grabación del video.
  • Un evento Stop que detiene una grabación inciada de video.

Nos centramos en la implementación del servicio. Contaremos con una
sencilla enumeración que nos permita determinar con facilidad el estado
de la grabación:

public enum RecordingStatus
{
     Stopped,
     Recording,
     Failed,
     Sucessfull
};

Sencillo, ¿cierto?.

Comenzar la grabación del video

Nos centramos en el método Start de nuestro servicio. Comenzamos creando un objeto de clase ScreenCapture utilizando el método: GetForCurrentView:

//Inicializamos ScreenCapture.
ScreenCapture screenCapture = ScreenCapture.GetForCurrentView();

A continuación, creamos una instancia de la clase MediaCaptureInitializationSettings y establecemos la fuente de audio y vídeo con las propiedades AudioSource y VideoSource del objeto ScreenCapture previamente definido:

// Establecemos MediaCaptureInitializationSettings para que ScreenCapture capture audio y video.
var mediaCaptureInitializationSettings = new MediaCaptureInitializationSettings
{
     VideoSource = screenCapture.VideoSource,
     AudioSource = screenCapture.AudioSource,
     StreamingCaptureMode = StreamingCaptureMode.AudioAndVideo
};

El objeto MediaCaptureInitializationSettings nos permite establecer la
configuración básica necesaria para crear un objeto de tipo MediaCapture. El objeto MediaCapture es el encargado de ofrecernos la posibilidad de capturar fotos, audio y vídeos.

// Inicializamos MediaCapture con los settings anteriores.
_mediaCapture = new MediaCapture();
await _mediaCapture.InitializeAsync(mediaCaptureInitializationSettings);

Inicializamos utilizando el método InitializeAsync pasándole como parámetro la configuración anterior.

NOTA: InitializeAsync iniciará una solicitud de consentimiento para obtener permisos de usuario.

Continuamos suscribiéndonos a los eventos Failed, RecordLimitationExceeded, y SourceSuspensionChanged:

_mediaCapture.Failed += (s, e) => { _recordingStatus = RecordingStatus.Failed; };
_mediaCapture.RecordLimitationExceeded += s => { _recordingStatus = RecordingStatus.Failed; };
 
screenCapture.SourceSuspensionChanged += (s, e) => Debug.WriteLine("IsAudioSuspended:" +
                                                                   e.IsAudioSuspended +
                                                                   " IsVideoSuspended:" +
                                                                   e.IsVideoSuspended);

Tenemos:

  • El evento Failed se lanzará cuando cualquier tipo de error ocurra durante la grabacion del video.
  • El evento RecordLimitationExceeded se lanzará cuando se supere el tiempo máximo de grabación. En Windows 8.1 el tiempo máximo de grabación es de 3 horas.
  • El evento SourceSuspensionChanged se lanzará cada
    vez que se cambie el estado de activo y suspensión de la aplicación
    durante la grabación del video. Profundizaremos en la gestión de la
    grabación del video y la suspensión de la aplicación algo más adelante
    en este mismo artículo.

A continuación, definimos el perfil de codificación para el archivo
de video y audio. Para ello, utilizamos un objeto de la clase MediaEncondingProfile. Tenemos disponible los  formatos más habituales tanto de video como de audio:

  • MP3
  • MP4
  • Wav
  • Wma
  • Wmv
// Creamos un encondig a utilizar. Por defecto, MP4 1080P.                  
MediaEncodingProfile mediaEncodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.HD1080p);

Tras crear el perfil de codificación, creamos el archivo donde se guardarán los medios capturados:

// Creamos el fichero resultante de la grabación.            
StorageFile video =
                    await
                        ApplicationData.Current.LocalFolder.CreateFileAsync(string.Format("{0}.mp4", recordName),
                            CreationCollisionOption.ReplaceExisting);

Por último, utilizaremos el método StartRecordToStorageFileAsync para comenzar la grabación:

// Con el formato, calidad y archivo destino definidos, comenzamos a grabar.
IAsyncAction startAction = _mediaCapture.StartRecordToStorageFileAsync(mediaEncodingProfile, video);
startAction.Completed += (info, status) =>
{
     if (status == AsyncStatus.Completed)
          _recordingStatus = RecordingStatus.Recording;
     if (status == AsyncStatus.Error)
     {
          _recordingStatus = RecordingStatus.Failed;
          Debug.WriteLine(info.ErrorCode.Message);
     }
};

Detener la grabación del video

Para detener la grabación del video utilizamos el método StopRecordAsync.

public void Stop()
{
     //Detenemos la grabación.           
     IAsyncAction stopAction = _mediaCapture.StopRecordAsync();
     stopAction.Completed += (info, status) =>
     {
          if (status == AsyncStatus.Completed)
               if (_recordingStatus == RecordingStatus.Recording)
                    _recordingStatus = RecordingStatus.Sucessfull;
     };
}

Gestion de la suspensión

Ya hemos mencionado el evento SourceSuspensionChanged. Ante
ciertas circunstancias la grabación se suspende para ser reanudada tras
finalizar la acción que provocó la suspensión. El video y el audio se
pueden bloquear de manera independiente por lo que en ciertas
circunstancias se detendrá la grabación de video, en otras las de audio y
en ocasiones ambas. Entre alguna de las situaciones que provocan a
detención de la grabación tenemos:

  • Una llamada entrante. Detiene la grabación de video y audio.
  • Notificaciones con información personal del usuario.
  • Cuando la aplicación no esta en primer plano.
  • Cuando se reproduce sonido en background se detiene la grabación de audio.

Con el evento SourceSuspensionChanged podemos detectar si se ha detenido la grabacion de video y audio gracias a las propiedades IsVideoSuspended y IsAudioSuspended
respectivamente. Podemos utilizar las propiedades para notificar al
usuario que se ha detenido la grabacion. Sin embargo, para reanudar la
misma no tenemos que hacer nada.

Buenas prácticas

Para no interferir con otras aplicaciones que el usuario pueda
utilizar cuando suspende nuestra aplicación, debemos limpiar los
recursos de captura utilizados en la suspensión.

Para realizar esta tarea creamos una propiedad pública con un objeto de tipo MediaCapture en el archivo App.xaml.cs:

public MediaCapture MediaCapture { get; set; }

Establecemos la propiedad en nuestro servicio:

// Establecemos el MediaCapture de App.xaml.cs para gestionar la suspensión.
var app = Application.Current as App;
if (app != null) app.MediaCapture = _mediaCapture;

En el evento OnSuspending realizaremos la detención de la grabación y la liberación de recursos:

if (MediaCapture != null)
{
     await MediaCapture.StopRecordAsync();
 
     MediaCapture.Dispose();
}

Podéis descargar el ejemplo realizado a continuación:

Más información

[Evento CartujaDotNet] Sevilla Mobility Day: Strikes Back

El evento

Tras el éxito de registro y asistencia al primer Sevilla Mobility Day, desde CartujaDotNet no podíamos más que repetir la formula. De esta forma nos llega la segunda edición, Sevilla Mobility Day: Strikes Back.

En
esta ocasión, hemos tomado todo lo bueno del evento anterior, hemos
analizado los detalles que debíamos mejorar y el resultado creemos que
es muy interesante. Tendremos  una mañana con repleta de sesiones
técnicas hablando de como integrar Cortana con aplicaciones Windows Phone, monetización de Apps con Fortumo Mobile, integrar Windows Phone con Pebble, generación de backends con AppNow y desarrollo de Webapps. Y si te pudiese parecer poco, en esta ocasión organizamos además una mesa redonda sobre TDD.

¿Te apuntas?

Fecha

El evento tendrá lugar el próximo Sábado, 25 de Octubre de 9:00h a 14:30h. Cada charla tendrá una duración de 40 minutos con descanso intermedio de 5 minutos.

NOTA: Tras las dos primeras sesiones tendremos una pausa de 15 minutos para reponer fuerza.

Lugar

Tendrá lugar en el Cloud Pointing de Sevilla situado en el Parque Empresarial Nuevo Torneo. Tenéis la información exacta del lugar a continuación:

c Biología, 12, Edificio Vilamar 2, 3ª Planta
Parque Empresarial Nuevo Torneo
41015 Sevilla

Agenda y Ponentes

El evento cuenta con una gran variedad de ponentes de lujo:

  • 9:00h – 9:05h: Bienvenida.
  • 9:10h – 9:50h: Un servidor realiza un recorrido por todos los aspectos a tener en cuenta para integrar nuestras aplicaciones Windows Phone con Cortana.
  • 9:55h – 10:35h: Josué Yeray nos introducirá Fortumo Mobile Payments, sistema de pago en aplicaciones universales.
  • 10:50h – 11:30h: Roberto Luis Bisbé nos mostrara como conectar Windows Phone con otros dispositivos.
  • 11:35h – 12:15h: De la mano de Asier Marques tendremos una interesante sesión donde aprenderemos a realizar WebApps.
  • 12:20h – 13:00h: Tras tanto fronted nos llega el turno del backend. Pedro J. Molina nos explicará como crear backends para nuestras aplicaciones con App Now.
  • 13:05h – 15:45h: David Rodriguez nos cuenta su experiencia con GeoMotion, App móvil asociada al localizador GPS para automóviles desde su inicio hasta hoy día.
  • 13:50h – 14:30h: Finalizamos el evento con una interesante y muy divertida mesa redonda junto a Juan María Lao, ¿TDD a favor o en contra?

Más información

[Evento WPSUG] Monetización con Fortumo Mobile Payments

Introducción

Volvemos a la carga en WPSUG, grupo de usuarios hispanos de Windows Phone,
con un nuevo Hangout sobre desarrollo en Windows y Windows Phone. En
esta ocasión, trataremos un punto fundamental y prioritario como
desarrolladores de aplicaciones móviles, la monetización
de las mismas. Una forma sencilla de gestionar la monetización es
utilizando las APIs de In App Purchase de WinRT. En la mayoría de
ocasiones, no tenemos ningun problema asociado. Sin embargo, debemos
tener en cuenta que en estos casos el pago es mediante una tarjeta de
crédito asociada a la cuenta de la tienda. No todo el mundo cuenta con
tarjeta de crédito, de hecho, si pensamos en ciertos países el problema
se acentúa. En algunos países, Microsoft ya soporta pagos con el
operador móvil, pero solo contamos con 37 de los 191 países donde se
encuentra la tienda disponible. Para mejorar esta situación contamos con
Fortumo Mobile Payments, que incrementa y mejora las opciones de pago. En este evento:

  • Aprenderemos que es Fortumo Mobile Payments.
  • Analizaremos todas sus características principales.
  • Integraremos el sistema de pago en una aplicación universal.

El evento

El próximo Miércoles 22 de Octubre, a las 18:00 (GMT+1) 
tendra lugar un Hangout en el que tendremos el placer de contar con un
ingeniero de Fortumo Mobile, que nos contará de primera mano todos los
detalles relacionados con la monetización en Windows y Windows Phone con
Fortumo. La sesión sera en ingles. Sin embargo, estaremos tanto Josué Yeray como un servidor para ayudar y gestionar dudas y otros detalles en español.

¿Te apuntas?

Más información

[Evento] Material del Madrid Mobility Day

El evento

El pasado Martes, 30 de Septiembre tuve el enorme placer de participar en el Madrid Mobility Day junto a Josué Yeray, Alejandro Campos y Luis Guerrero.
El evento constaba de múltiples sesiones de desarrollo para Windows y
Windows Phone, publicación y marketing, desarrollo de videojuegos con Unity y desarrollo de aplicaciones móviles multiplataforma con Xamarin.

Las charlas

Participé con dos charlas de desarrollo:

  • Desarrollo de aplicaciones Windows Phone con Silverlight 8.1.
  • Introducción al desarrollo de apps móviles multiplataforma con Xamarin.Forms. En esta ocasión con la inestimable ayuda de Josué Yeray.

Desarrollo de aplicaciones Windows Phone con Silverlight 8.1

Con la llegada de Windows Phone 8.1 tenemos nuevas formas posibles de
desarrollar nuestras aplicaciones. Por un lado se habla de Silverlight
8.1, por otro de Windows XAML, WinJS, etc. La idea de la charla era:

  • ¿Que diferencia hay entre Silverlight 8.1 y Windows XAML?
  • ¿Si ya tengo una App Windows Phone 8.0, que uso?
  • ¿Y si es Windows Store?

En Windows Phone 8.1 podemos desarrollar con:

  • Silverlight Windows Phone 8.0: Todas las
    aplicaciones Windows Phone 8.0 funcionan en Windows Phone 8.1 aunque
    evidentemente sin tener acceso a las nuevas APIs.
  • Silverlight 8.1: Nueva versión destinada a migrar aplicaciones con rapidez y sencillez.
  • Windows XAML: Gran novedad, llega a Windows Phone
    una nueva versión de XAML, el ya usado en aplicaciones WinRT. La
    convergencia entre las paltaformas se potencia gracias a esta nueva
    opción dando lugar a los proyectos universales.
  • WinJS: Permite desarrollar aplicaciones nativas con
    HTML5, CSS y JS. Ahora además de aplicaciones Windows Store permite
    crear aplicaciones Windows Phone, incluso aplicaciones universales.

Las conclusiones básicas de la charla fueron:

  • Si tienes una aplicación Windows Phone 8.0 y no necesitas ninguna de
    las nuevas APIs disponibles en Windows Phone 8.1 no tienes que hacer
    nada. Las aplicaciones Windows Phone 8.0 funcionan en los dispositivos
    Windows Phone 8.1.
  • Si tienes una aplicación Windows Phone 8.0 y quieres utilizar las
    nuevas APIs de Windows Phone 8.1, Silverlight 8.1 es una buena opción.
    Silverlight 8.1 nos permite migrar aplicaciones con suma facilidad. Si
    tu aplicación utiliza:

    • CameraCaptureTask
    • Camera Lenses
    • Lockscreen background image provider
    • Alarmas
    • Recordatorios

Silverlight 8.1 es tu opción ya que estas opciones son exclusivas de Silverlight.

  • Sin embargo, hay opciones disponibles en Windows Phone 8.0 que no
    estan disponibles en Silverlight 8.1 como por ejemplo Background Audio.
    En este caso Windows XAML es la opción adecuada.
  • Si partimos de una aplicación Windows Store, Windows XAML es más directo.
  • Si partimos de una aplicación Windows Store desarrollada con WinJS, utilizar WinJS para Windows Phone es lo más idóneo.
  • Si partimos de cero, podemos elegir entre Windows XAML, WinJS o
    Silverlight 8.1. Todo depende de los conocimientos que tengas en los
    lenguajes y que quieras realizar. Si quieres cubrir teléfonos y tabletas
    (aplicaciones Windows Phone y Windows Store), realizar una aplicación
    universal es lo más idóneo.

Introducción al desarrollo de apps móviles multiplataforma con Xamarin.Forms

Con la reciente actualización a la versión 3 de Xamarin nos llega Xamarin.Forms. Es un toolkit para crear una abstracción sobre la interfaz de usuario de Android, iOS y Windows Phone permitiendo desarrollarla una única vez con código C# o Extensible Application Markup Language (XAML).

En esta sesión junto a Josué Yeray teníamos como objetivos:

  • Trasmitir en que consiste y como funciona Xamarin.Forms.
  • Crear y explicar una App desde cero.
  • Aplicar MVVM.
  • Comparar con alternativas como MVVMCross.

El material

Desarrollo de aplicaciones Windows Phone con Silverlight 8.1

Os dejo a continuación la presentación utilizada en esta sesión:

 

Además de los ejemplos.

Introducción al desarrollo de apps móviles multiplataforma con Xamarin.Forms

Presentación utilizada en esta sesión:

 

Y ejemplos.

Extra

No quisiera terminar sin agradecer a los chicos de DX por su colaboración,  facilitarnos la sala y en definitiva hacer que todo sea tan sencillo. También me gustaría agradecer a Cristina Guerrero, nuestra MVP Lead
por realizarnos una visita. Era la primera vez que la conocía en
persona y solo puedo decir que es aun más encantadora en persona si
cabe. Y por supuesto, como no, gracias a todos los asistentes.

Más información

[Universal App] Usando Microsoft OCR

Introducción

Existen aplicaciones sumamente útiles en la Tienda. Algunas de ellas
impactantes. Personalmente me impresionaron alguna aplicación que
directamente de una foto o video podía capturar el texto y traducirnoslo
directamente a nuestron idioma, o aplicaciones que de una captura nos
obtienen el texto de la misma permitiendonos guardarlo o incluso
compartirlo. Son aplicaciones muy útiles en categorías diferentes que
tienen un denominador común, son capaces de obtener el texto de una imagen.

¿Cómo lo hacen?

OCR

OCR son las siglas de Optical character recognition,
o en español reconocimiento óptico de carácteres. Es un proceso
dirigido a la digitalización de textos, los cuales identifican
automáticamente a partir de una imagen símbolos o caracteres. Las
posibilidades obtenidas son muchas y variadas:

  • Obtener el texto de una imagen.
  • Traducir el texto de una imagen.
  • Verificar si una palabra o valor se encuentra en el texto de la imagen.
  • Etc.

Librería Microsoft OCR para Windows Runtime

Recientemente Microsoft ha liberado en NuGet la librería Microsoft OCR
para Windows Runtime. Esta librería nos permite en aplicaciones
universales digitalizar textos desde imagenes. La librería funciona
completamente en local tratando imágenes desde la cámara, local o desde
la red soportando hasta 21 idiomas.

Utilizando la librería

Comenzamos creando un nuevo proyecto:

Añadimos las carpetas Views, ViewModels y Services además de las clases base necesarias para implementar el patrón MVVM de la misma forma que vimos en este artículo.

Nuestro objetivo sera muy sencillo. Nuestra aplicación de ejemplo obtendrá una imagen local gracias al uso del FileOpenPicker para sintetizar la imagen obtenida con la librería Microsoft OCR.

La interfaz de usuario

Comenzamos creando la interfaz de nuestro ejemplo. En la carpeta Views tenekos disponible la vista MainView. Añadimos:

<ScrollViewer>
     <StackPanel>
          <Image Source="{Binding Bitmap}" Stretch="Uniform" MaxHeight="300" Margin="10" />
          <TextBlock Text="{Binding Text}" TextWrapping="Wrap" FontSize="24"/>
     </StackPanel>
</ScrollViewer>

Hemos añadido dos controles básicos para nuestro ejemplo. Por un lado
la imagen bindeada a una propiedad Bitmap que mostrará la imagen
obtenida con el FileOpenPicker, por otro lado añadimos un sencillo TextBlock que mostrará el resultado de obtener el texto correspondiente a la imagen cargadada.

En la vista principal trendremos además dos botones. Un botón para
obtener una imagen local, y otro para utilizar la imagen obtenida para
extraer el texto:

<Page.BottomAppBar>
     <CommandBar>
          <AppBarButton Label="get picture" Icon="Pictures" Command="{Binding FileOpenPickerCommand}" />
          <AppBarButton Label="get text" Icon="Forward" Command="{Binding GetTextCommand}" />
     </CommandBar>
</Page.BottomAppBar>

Los añadimos en la CommandBar de la página. En la viewmodel
de la vista tendremos disponibles tanto la imagen como el texto
bindeados asi como los dos comandos necesarios para ejecutar las
acciones requeridas:

//Variables
private WriteableBitmap _bitmap;
private string _text;
 
//Commands
private ICommand _fileOpenPickerCommand;
private ICommand _getTextCommand;
 
public WriteableBitmap Bitmap
{
     get { return _bitmap; }
     set
     {
          _bitmap = value;
          RaisePropertyChanged("Bitmap");
     }
}
 
public string Text
{
     get { return _text; }
     set
     {
          _text = value;
          RaisePropertyChanged("Text");
     }
         
public ICommand FileOpenPickerCommand
{
     get { return _fileOpenPickerCommand = _fileOpenPickerCommand ?? new DelegateCommandAsync(FileOpenPickerCommandDelegate); }
}
 
public ICommand GetTextCommand
{
     get { return _getTextCommand = _getTextCommand ?? new DelegateCommandAsync(GetTextCommandDelegate); }
}
public async Task FileOpenPickerCommandDelegate()
{
 
}
 
public async Task GetTextCommandDelegate()
{
 
}

Añadiendo la librería

Continuamos añadiendo la librería.

La librería la tenemos disponible en NuGet por lo que podemos instalarlo usando Nuget Package Manager. En las referencias del proyecto hacemos clic derecho y seleccionamos la opción Manage NuGet Packages …

En la ventana modal que nos aparece, en la parte superior derecha donde podemos realizar una búsqueda, buscamos por “Microsoft OCR”:

Seleccionamos el elemento “Microsoft OCR Library for Windows Runtime” y pulsamos el botón Install.
Tras un breve periodo donde se procede a descargar e incluir las
librerías en las referencias del proyecto, tendremos lo necesario para
comenzar a trabajar con OCR.

FileOpenPicker

Representa un elemento de interfaz que permite al usuario elegir y
abrir ficheros. Es una API asíncrona disponible dentro del namespace Windows.Storage.Pickers. La API esta disponible tanto en Windows como en Windows Phone pero con diferencias entre ambas plataformas.

En aplicaciones Windows Store se realiza una llamada asíncrona a la
API esperando el resultado directamente. Mientras que en Windows Phone
el proceso es algo más complejo. En Windows Phone podemos contar con
dispositivos de baja memoria. Por ese motivo, en se utilizan métodos “AndContinue”.
Esto quiere decir que al realizar la llamada a la API la aplicación es
suspendida e incluso podría llegar a ser terminada. Continuará el
proceso al reactivar la aplicación.

Debido a las diferencias entre ambas plataformas, en nuestro ejemplo, vamos a crear una interfaz comun de un servicio FileOpenPicker en el proyecto Shared:

public interface IFilePickerService
{
     void Initialise();
     Task<StorageFile> ShowPickerAsync(FileOpenPicker picker);
}

Realizaremos la implementación adecuada de cada plataforma en el proyecto correspondiente.

Windows Store

Conenzamos por la implementacion en la aplicación Windows Store que es el caso más sencillo. El FileOpenPicker  es invocado llamando al método PickSingleFileAsync que devolverá (asíncronamente) un objeto de tipo StorageFile que representa el fichero seleccionado por el usuario:

public async Task<StorageFile> ShowPickerAsync(FileOpenPicker picker)
{
     StorageFile file = await picker.PickSingleFileAsync();
     return (file);
}

Sencillo y brutalmente potente.

Windows Phone

Continuamos con Windows Phone. En este caso, el FileOpenPicker es invocado mediante el evento PickSingleFileAndContinue. La aplicación pasa a estar suspendida.

public async Task<StorageFile> ShowPickerAsync(FileOpenPicker picker)
{
     _completionSource = new TaskCompletionSource<StorageFile>();
 
     picker.PickSingleFileAndContinue();
 
     StorageFile file = await _completionSource.Task;
 
     return (file);
}

Una vez resumida se obtiene el objeto de tipo StorageFile vía método Activated de la aplicación. La clase FileOpenPickerContinuationEventArgs nos proporciona información acerca del evento Activated cuando se produce por una operación de FileOpenPicker.

private void OnApplicationActivated(CoreApplicationView sender,
            IActivatedEventArgs args)
{
     var continueArgs =
                args as FileOpenPickerContinuationEventArgs;
 
     if (continueArgs != null)
     {
          _selectedFile = continueArgs.Files[0];
 
         if (_completionSource != null)
         {
              _completionSource.SetResult(_selectedFile);
              _completionSource = null;
         }
     }
}

Con esto ya tenemos la capacidad en nuestra aplicación, tanto en
Windows como en Windows Phone, de permitir seleccionar una imagen al
usuario.

Microsoft OCR

Llegamos al eje central del ejemplo. La librería Microsoft OCR nos
permite extraer el texto de la imagen obtenida previamente con el FileOpenPicker.
La librería Microsoft OCR para Windows Runtime nos permite extraer el
texto de una imagen además de poder encontrar patrones como correos o
números de teléfono, ideal para pooder ejecutar acciones.

Vamos a crear un servicio (al igual que hicimos con el
FileOpenPicker) para inyectarlo posteriormente con inyección de
dependencias. La interfaz del servicio es la siguiente:

public interface IOcrService
{
     Task<string> GetText(WriteableBitmap bitmap);
}

Muy muy simple. Tendremos un único método asíncrono que obtendra la
imagen y devolverá el texto. Trabajamos con la librería OCR en el
namespace WindowsPreview.Media.Ocr. La implementación del servicio para ambas plataformas es la siguiente:

public class OcrService : IOcrService
{
     private OcrEngine _ocrEngine;
 
     public async Task<string> GetText(WriteableBitmap bitmap)
     {
         string result = string.Empty;
 
         if (_ocrEngine == null)
             _ocrEngine = new OcrEngine(OcrLanguage.English);
 
         // Sintetizamos la imagen para extraer el texto (RecognizeAsync)
         var
ocrResult = await _ocrEngine.RecognizeAsync((uint)bitmap.PixelHeight,
(uint)bitmap.PixelWidth, bitmap.PixelBuffer.ToArray());
 
         // Si el resultado no contiene líneas no hacemos nada
         if (ocrResult.Lines != null)
             // Si hay líneas, las vamos añadiendo al resultado final
             result
= ocrResult.Lines.Aggregate(result, (current1, line) =>
line.Words.Aggregate(current1, (current, word) => current + word.Text
+
" "));
 
         return result;
     }
}

Analicemos con calma el código anterior. Lo primero que hacemos es crear una instancia de OcrEngine.
Esta clase es la encargada de proporcionar la capacidad de realizar OCR
a nuestra aplicación. Al instanciar el OcrEngine podemos hacerlo sin
parámetros o indicando el idioma a utilizar para
detectar el texto en la imagen. Hay 21 lenguajes soportados. Dependiendo
de la calidad de detección, el rendimiento y otros parámetros podemos
establecer la siguiente divisón en grupos:

  • Excelente: Checo, Danés, Holandés, Inglés, Finlandés, Francés, Alemán, Húngaro, Italiano, Noruego, Polaco, Portugués, Español y Sueco.
  • Muy bueno: Chino, Griego, Japones, Ruso y Turco.
  • Bueno: Chino tradicional y Creano.

NOTA: Al incluir la librería Microsoft OCR
además de la propia librería se nos añade un archivo de recursos OCR.
Estos recursos son utilizados para un correcto reconocimiento del texto
correspondiente en el idioma deseado. El archivo de recursos OCR añadido
por defecto es en ingles. Si deseamos utilizar otros idiomas a los
recursos OCR debemos utilizar la herramienta OCR Resources Generator tool. En el siguiente apartado de este mismo artículo utilizaremos la herramienta.

Continuamos analizando el código de nuestro servicio OCR. Tras instanciar el OcrEngine, utilizamos el método RecognizeAsync. A este método le pasamos la imagen junto con sus dimensiones para extraer el texto. Se devuelve un objeto de tipo OcrResult. Este objeto contiene el texto extraido asi como sus posiciones y tamaños.

El objeto OcrResult cuenta con una colección de objetos de tipo OcrLine que son cada una de las líneas de texto extraidas que a su vez contienen una colección de objetos de tipo OcrWord, que contienen la información de cada una de las palabras extraidas.

Iremos recorriendo las líneas añadiendo cada palabra en una cadena que sera el resultado devuelto por nuestro servicio.

El uso en nuestra viewmodel sera simple:

Text = await _ocrService.GetText(_bitmap);

Donde _bitmap representa la imagen local obtenida. Guardamos
en Text el resultado obtenido. En nuestro ejemplo, para simplificar
solo obtenemos el texto y nuestro objetivo finaliza aqui. Sin embargo,
desde este punto podéis utilidad OCR para una enorme cantidad de
situaciones como traducciones, extraer ciertos campos, verificar si la
iamgen contiene o no cierta palabra, compartir el contenido, etc.

Continuamos el ejemplo. La librería OCR tiene límites.
La dimensión de la imagen utilizada no puede ser inferior de 40 x 40px o
superior a 2600 x 2600px. Debemos considerar esto en nuestras
aplicaciones. Definimos los límites en constantes:

public const int MinWidth = 40;
public const int MaxWidth = 2600;
public const int MinHeight = 40;
public const int MaxHeight = 2600;

De modo que antes de utilizar nuestro servicio OCR para extraer el texto realicemos la verificación correspondiente:

public async Task GetTextCommandDelegate()
{
     // Verificamos si la imagen cumple con las características necesarias para ser procesada.
     // Las dimensiones soportadas son desde 40 a 2600 pixels.
     if (_bitmap.PixelHeight < MinHeight ||
         _bitmap.PixelHeight > MaxHeight ||
         _bitmap.PixelWidth < MinWidth ||
         _bitmap.PixelWidth > MaxHeight)   
         await _dialogService.ShowAsync("Imagen inválida", "La imagen no esta dentro del tamaño soportado.");
     else    
         Text = await _ocrService.GetText(_bitmap);
}

Todo listo!. Si ejecutamos el ejemplo y probamos:

Como generar recursos OCR

Hasta este punto tenemos lo necesario para saber como utilizar la librería Microsoft OCR
y extraer texto de una imagen. Sin embargo, en el proceso de extracción
como ya mencionamos previamente se utilizan unos
recursos (MsOcrRes.orp) localizados por idioma que facilitan la calidad
del proceso.

Hasta ahora hemos utilizado el ingles (idioma por defecto), pero… ¿que ocurre si intentamos extraer texto en japones?

Bueno, para lograr ese objetivo con l mayor calidad posible tenemos a nuestra disposición la herramienta OCR Resources Generator tool. Si nos paramos a anlizar la estructura de nuestro proyecto, tendremos algo similar a:

<solution_name>
   <project_name>
      OcrResources
         MsOcrRes.orp
   packages
      Microsoft.Windows.Ocr.1.0.0
         build
         lib
         content
            OcrResources
               MsOcrRes.orp
         OcrResourcesGenerator
            OcrResourcesGenerator.exe

Tenemos disponible la herramienta en <solution_name>packagesMicrosoft.Windows.Ocr.1.0.0OcrResourcesGeneratorOcrResourcesGenerator.exe. Tras ejecutarla veremos una pantalla como la siguiente:

Nos permite elegir entre los 21 idiomas soportados.Podemos añadir o
quitar idiomas y una vez esta a nuestro antojo pulsaremos el botón Generate Resources.

Nos aparecerá una ventana que nos permite guardar el nuevo archivo de
recursos OCR. Una vez guardado bastara con reemplazar el archivo
añadido por defecto en OcrResourcesMsOcrRes.orp.

Sencillo, ¿verdad?

Podéis descargar el ejemplo realizado a continuación:

Más información

[Windows Phone 8.1] Update Task

Introducción

Con la llegada de nuevo SDK siempre esperamos novedades
significativas que nos permitan crear cada vez mejores aplicaciones y
otorgar experiencias de usuario más completas. Con la llegada del SDK de
Windows Phone 8.1 contamos con nuevos controles, nuevas APIs,
herramientas, etc.

Entre la enorme cantidad de novedades contamos con una nueva background task realmente útil llamada Update Task.

Como podemos adivinar por su nombre, este background task se ejecuta
cuando la aplicación se actualiza. Esto nos permite mostrar información
al usuario, actualizar datos, actualizar settings, etc.

En este artículo vamos a aprender como utilizar el Update Task.

¿Te apuntas?

Creando el Update Task

Teniendo una aplicación Windows Phone 8.1 nos centramos en añadir la background task. Para añadir la background task debemos añadir un componente WinRT.

Una vez creado el componente WinRT renombraremos la clase a UpdateTask. La clase UpdateTask implementa la interfaz IBackgroundTask. Esta interfaz cuenta con un único método llamado Run. Este método sera al que el sistema llamará para iniciar la background task y es necesario en todas las tareas en segundo plano.

namespace UpdateTask
{
    public sealed class UpdateTask : IBackgroundTask
    {
        public void Run(IBackgroundTaskInstance taskInstance)
        {
 
        }
    }
}

NOTA:  La clase de la tarea en segundo plano debe ser una clase public y sealed.

La Task tendrá como objetivo notificar al usuario de una nueva versión. Por lo tanto, en el método Run vamos a lanzar una notificación Toast y vamos a actualizar el Tile de la aplicación.

Creamos un método para lanzar una notificación Toast:

/// <summary>
/// Muestra una notificación Toast para notificar al usuario de la nueva versión.
/// </summary>
private void ShowNotification()
{
     var toastnotifier = ToastNotificationManager.CreateToastNotifier();
     var toastDescriptor = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
     var txtNodes = toastDescriptor.GetElementsByTagName("text");
 
     txtNodes[0].AppendChild(toastDescriptor.CreateTextNode("Nueva versión!"));
     txtNodes[1].AppendChild(toastDescriptor.CreateTextNode(string.Format("Actualizada : {0}", DateTime.Now)));
 
     var toast = new ToastNotification(toastDescriptor);
 
     toastnotifier.Show(toast);
}

Utilizamos la clase PushNotificationChannelManager
encargada de crear objetos que se utilizan para recuperar canales de
notificaciones de inserción de Servicios de notificaciones de inserción
de Windows (WNS). Utilizamos el método CreateToastNotifier que crea una nueva instancia de ToastNotification, que permite generar una notificación Toast para la aplicación.

Otro método actualizará el Tile de la aplicación:

/// <summary>
/// Actualiza el Tile de la aplicación notificando de la nueva versión.
///
/// </summary>
private void UpdateTileStatus()
{
     var tileContent = TileUpdateManager.GetTemplateContent(
                       TileTemplateType.TileSquare150x150Text01);
 
     var tileText = tileContent.SelectNodes("tile/visual/binding/text");
 
     tileText[0].InnerText = "Nueva versión!";
     tileText[1].InnerText = "Actualizada";
     tileText[2].InnerText = DateTime.Now.ToString();
 
     var notification = new TileNotification(tileContent);
     var updater = TileUpdateManager.CreateTileUpdaterForApplication();
 
     updater.Update(notification);
}

La clase TileUpdateManager crea objetos de tipo TileUpdater utilizados para actualizar el Tile
de Aplicación. Esta clase también nos facilita el acceso al contenido
XML de las plantillas de Tile para poder personalizar dicho contenido.

En el método Run de la Task ejecutaremos ambos métodos:

public void Run(IBackgroundTaskInstance taskInstance)
{
     ShowNotification();
     UpdateTileStatus();
}

Una vez terminada nuestra Task debemos añadir la referencia a la misma de nuestro proyecto Windows Phone. Clic derecho, opción “Add references”:

Tras añadir la referencia al componente WinRT debemos realizar algunos cambios en el archivo Package.appxmanifiest. Nos dirigimos a la pestaña “Capabilites”. Añadimos una nueva capacidad de tipo Update Task:

En las propiedades de la capacidad debemos definir la propiedad Entry Point, es decir, el nombre completo de la clase de nuestra background task incluido namespace:

Y todo listo!

NOTA: Para que nuestro ejemplo funcione en su
totalidad antes de abandonar el archivo de manifiesto debemos activar la
capacidad de notificaciones Toast en nuestra aplicación.

Probando el Update Task

Es hora de verificar que todo funciona correctamente. Tras lanzar
nuestra aplicación al menos una vez, podemos simular una actualización
de la aplicación modificando la versión de la misma en el archivo Package.appxmanifiest.

Tras ejecutar la aplicación:

Recibiremos una notificación Toast indicandonos la nueva versión además de haber sido actualizado el Tile de la aplicación.

Podéis descargar el ejemplo realizado a continuación:

Más información

[Evento] Madrid Mobility Day

El evento

No hay duda, los smartphones han llegado, y ya forman parte de la
vida de todos nosotros. En muchos aspectos de nuestra vida accedemos a
información, realizamos algna tarea o sencillamente nos entretenemos con
uno de ellos.

Esto también nos afecta como desarrolladores. El desarrollo móvil se
ha convertido en una prioridad en una gran mayoria de ámbitos. Por ese
motivo, nace el evento Madrid Mobility Day. Un evento
que como su nombre indica se celebrará en Madrid e irá orientado al
desarrollo móvil. Tendremos múltiples sesiones de desarrollo para
Windows Phone, publicación y marketing, desarrollo de videojuegos con Unity y veremos nuevas herramientas para el desarrollo de aplicaciones móviles como Radarc Online.

¿Te apuntas?

Fecha

El evento tendrá lugar el próximo Martes, 30 de Septiembre de 9:00h a 14:00h.
Cada charla tendrá una duración de 45 minutos con descanso intermedio
de 5 minutos. Además, tendremos un descanso de 20 minutos a mitad de
mañana.

Lugar

Tendrá lugar en Microsoft Ibérica, concretamente en la sala Ramón y Cajal. Tenéis la información exacta del lugar a continuación:

Centro Empresarial La Finca – Paseo del Club Deportivo, 1
Pozuelo de Alarcón Madrid 28223
España
Microsoft Iberica

Microsoft Iberica

Agenda y Ponentes

La agenda del evento es la siguiente:

Ponencias Horario
Registro  9:00 – 9:15
Keynote 9:15 – 9:20
Introducción a Universal Apps 9:20 – 10:05
Introducción a Silverlight 8.1 10:10 – 10:55
Pausa 10:55 – 11:15
Publicación y Marketing de Universal Apps 11:15 – 12:00
Juegos con Unity 12:05 – 12:50
RadarC Online 12:55 – 13:40

El evento cuenta con una gran variedad de ponentes de lujo:

  • El evento comienza con Josué Yeray hablando de aplicaciones universales en Windows Phone. En esta sesión aprenderemos como desarrollar aplicaciones unviersales para Windows Phone 8.1 y Windows reutilizando la mayor parte del código.
  • Continuamos con otra sesión de la mano de un servidor. En esta sesión aprenderemos como migrar aplicaciones Windows Phone 8.0 a 8.1 y que novedades llegan con Silverlight 8.1.
  • Tras un merecido descanso el equipo de DX (Alejandro Campos y Luis Guerrero)
    remata un gran evento sobre desarrollo de aplicaciones Windows Store y
    Windows Phone con la publicación y marketing de las mismas además de
    adentrarnos en el desarrollo de videojuegos con Unity.
  • Finalizamos el evento con una sesión en la que hablaremos de Xamarin.Forms.

Más información

[Quedada CartujaDotNet] Vuelta al “cole”!

Quedada

En CartujaDotNet vamos a realizar una quedada
informal para charlar abiertamente sobre tecnologías Microsoft,
herramientas utilizadas, intercambiar impresiones, etc. Además, se
analizarán las próximas charlas ya planteadas y los eventos confirmados
entre otros temas de interés.

No hace falta confirmar asistencia, y por supuesto será gratuito.

¿Te apuntas?

A continuación tienes disponible la fecha, hora y lugar:

Más información

[Windows Phone 8.1] Crear menu lateral deslizante (similar al de la App Facebook)

Introducción

El SDK de Windows Phone es bastante versátil y nos proporciona una
fuente bastante extensa de controles como para realizar una interfaz de
usuario rica y atractiva. De hecho, tenemos ciertos controles como el
Hub o el Pivot encargados de crear la estructura principal de nuestra
aplicación determinando el acceso a los distintos apartados. Sin
embargo, no es una forma única y exclusiva. Son múltiples los casos de
aplicaciones en la tienda con ciertos menus deslizantes o determinos
apartados personalizados. Un ejemplo claro de ello es la aplicación de Facebook que cuenta con un menu deslizante como el siguiente:

¿Cómo realizamos dicho menu?

Bien, tenemos múltiples formas de lograrlo. Con el uso combinado de
paneles, animaciones y gestos podríamos conseguir reproducir el menu de
Facebook. Sin embargo, tenemos una librería llamada SlideView disponible
tanto para Windows Phone 8.0 como para Windows Phone 8.1 que tiene como
objetivo permitirnos crear un menu de este tipo con suma facilidad.

En este artículo vamos a aprender como crear menus deslizantes al estilo Facebook utilizando la librería SlideView.

¿Te apuntas?

Crear el menu en una vista

Comenzamos creando un nuevo proyecto:

Para crear el menu lateral deslizante tipo Facebook, como mencionamos
previamente vamos a utilizar una librería gratuita creada por Cyril Cathala, MVP de C# llamada SlideView.
La librería contiene múltiples controles inspirados por el menu
deslizante de Facebook que analizaremos poco a poco en este artículo.

Comenzamos añadiendo la librería.

La librería la tenemos disponible en NuGet por lo que podemos instalarlo usando Nuget Package Manager. En las referencias del proyecto hacemos clic derecho y seleccionamos la opción Manage NuGet Packages …

En la ventana modal que nos aparece, en la parte superior derecha donde podemos realizar una búsqueda, buscamos por “slideview”:

Seleccionamos el primero de los elementos y pulsamos el botón Install.
Tras un breve periodo donde se procede a descargar e incluir las
librerías en las referencias del proyecto, tendremos el siguiente
resultado:

Nos centramos en nuestra página principal, MainPage.xaml. Vamos a utilizar el control SlideView de la librería:

<Grid>
     <ctl:SlideView SelectedIndex="1">
          <Grid Background="Red"
                Width="350">
                <TextBlock Text="Left"
                           FontSize="48"
                           HorizontalAlignment="Center"/>
          </Grid>
          <Grid Background="LightGray">
                <TextBlock Text="Main Content"
                           FontSize="48"
                           HorizontalAlignment="Center"/>
          </Grid>
          <Grid Background="Firebrick"
                  Width="350">
                <TextBlock Text="Right"
                           FontSize="48"
                           HorizontalAlignment="Center"/>
          </Grid>
     </ctl:SlideView>
</Grid>

Es un control muy sencillo. En su interior iremos añadiendo paneles
que se apilaran uno tras otro de forma horizontal. Podemos establecer un
ancho fijo o dejar el ancho automático. En caso de dejar un ancho
automático, el panel se ajustará al ancho de la pantalla. Además,
podemos indicar el panel visible de forma muy simple mediante la
propiedad SelectedIndex del control.

El resultado es el siguiente:

Podéis descargar el ejemplo realizado a continuación:

Crear el menu a nivel de aplicación

El ejemplo anterior es muy simple y nos permite crear menus laterales
con suma facilidad. Sin embargo, los paneles laterales solo aparecerán
en la vista donde utilicemos el control.

¿Qué ocurre si deseamos los menus laterales a lo largo de toda la aplicación?

Para estos casos tenemos disponible en la librería otro control, variante del Frame, llamado SlideApplicationFrame. Para aprender a utilizar este frame vamos a crear otro proyecto diferente al anterior. Añadimos las carpetas Views, ViewModels y Services además de las clases base necesarias para implementar el patrón MVVM de la misma forma que vimos en este artículo.

Para utilizar el control, necesitamos sustituir el Frame de la aplicación por el frame de tipo SlideApplicationFrame. Una forma sencilla de definir el nuevo frame es directamente en XAML en App.xaml:

<ctl:SlideApplicationFrame Header="Slide View"
                           Background="Green"
                           x:Key="RootFrame">
     <ctl:SlideApplicationFrame.LeftContent>
          <shell:LeftView />
     </ctl:SlideApplicationFrame.LeftContent>
     <ctl:SlideApplicationFrame.RightContent>
          <shell:RightView />
     </ctl:SlideApplicationFrame.RightContent>
</ctl:SlideApplicationFrame>

Definimos el contenido del menu lateral izquierdo mediante la propiedad LeftContent y el derecho mediante RightContent.
En cada panel podemos incluir una vista con su contenido y gestionada
por su propio viewmodel. El contenido del menu lateral izquierdo:

<Grid x:Name="LayoutRoot"
      Background="LightBlue">
     <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition Height="*" />
     </Grid.RowDefinitions>
     <Grid Background="Blue">
          <TextBlock Margin="6,12"
                     HorizontalAlignment="Center"
                     Text="Left View" />
     </Grid>
     <Grid Grid.Row="1">
          <TextBlock Text="Left side!"/>
     </Grid>
</Grid>

El resultado:

El menu lateral derecho es otra vista con el siguiente contenido:

<Grid x:Name="LayoutRoot"
      Background="Orange">
      <Grid.RowDefinitions>
           <RowDefinition Height="Auto" />
           <RowDefinition Height="*" />
      </Grid.RowDefinitions>
      <Grid Background="OrangeRed">
           <TextBlock Margin="6,12"
                      HorizontalAlignment="Center"
                      Text="Right View" />
      </Grid>
      <Grid Grid.Row="1">
           <TextBlock Text="Right side!"/>
      </Grid>
</Grid>

El resultado:

NOTA: Podemos personalizar la cabecera del control, los botones para expandir cada menu e incluso el panel principal (LeftPanelButton, MainPanel, etc).

Una vez definido el frame SlideApplicationFrame bastará con acceder a el y reemplazar el frame de la aplicación, rootFrame:

rootFrame = this.Resources["RootFrame"] as SlideApplicationFrame;

Sencillo, ¿verdad?

Un detalle más…

Aunque no esta directamente relacionado con los menus laterales, la librería cuenta con otro control más llamado AutoHideBar.
El control AutoHideBar se muestra cuando realizamos scroll hacia arriba
en la parte superior de un listado y se oculta al hacer scroll hacia
abajo. Vamos a utilizar el control. Su definición es sencilla:

<ctl:AutoHideBar />

El objetivo del control es mostrar información o botones de acción al
hacer scroll hacia la parte superior de una lista. Por ese motivo, para
poder usar el control necesitaremos, un control listado. En la viewmodel de la vista vamos a definir primero una colección:

private ObservableCollection<string> _list;
 
public ObservableCollection<string> List
{
     get { return _list; }
     set { _list = value; }
}

Creamos un método que rellenará la propiedad List con datos:

private void FillData()
{
     for(int i = 0; i < 50; i++)
     {
          _list.Add(string.Format("List Item Number {0}", i + 1));
     }
}

Por último, en la vista, definiremos un control ListView con la propiedad ItemsSource bindeada a la propiedad List:

<ListView x:Name="List"
           ItemsSource="{Binding List}">
     <ListView.Header>
          <Grid Height="80"/>
     </ListView.Header>
     <ListView.ItemTemplate>
          <DataTemplate>
               <Grid>
                    <TextBlock Text="{Binding}"
                               FontSize="18" />
               </Grid>
          </DataTemplate>
     </ListView.ItemTemplate>
</ListView>

Utilizamos la propiedad Header del ListView para establecer un encabezado y el control AutoHideBar:

<ctl:AutoHideBar ScrollControl="{Binding ElementName=List}"
                 Background="DarkGreen">
     <Grid>
          <TextBlock Text="AutoHideBar"
                     HorizontalAlignment="Center" />
     </Grid>
</ctl:AutoHideBar>

Para que el control AutoHideBar funcione correctamente, necesitamos bindear el control lista en la propiedad ScrollControl del control AutoHideBar.

Podéis ver al Frame SlideApplicationFrame y al controlAutoHideBar en acción en el siguiente video:

Podéis descargar el ejemplo realizado a continuación:

Más información