[Windows 10] Utilizando x:Bind en un diccionario de recursos

Introducción

Data binding es un mecanismo mediante el cual
podemos enlazar los elementos de la interfaz de usuario con los objetos
que contienen la información a mostrar. Cuando realizamos data binding,
creamos una dependencia entre el valor de una propiedad llamada target con el valor de otra propiedad llamada source. Donde normalmente, la propiedad target recibirá el valor de la propiedad source.

Es el mecanismo base que nos permite utilizar el patrón MVVM en nuestras Apps móviles logrando:

  • Nos permite dividir el trabajo de manera muy sencilla (diseñadores – desarrolladores)
  • El mantenimiento es más sencillo.
  • Permite realizar Test a nuestro código.
  • Permite una más fácil reutilización de código.

Sin embargo, además de toda la potencia mencionada teníamos ciertas
limitaciones. Los errores de Binding no se producían en tiempo de
compilación de la App además de tener diferentes mejoras relacionadas
con el rendimiento. Limitaciones existentes hasta ahora…

Con la llegada de Windows 10 tenemos la posibilidad de crear bindings compilados en lugar de los bindings clásicos.

x:Bind

x:Bind es una nueva síntaxis en XAML que cubre un objetivo similar a
Binding. Permite crear un enlace a datos pero con significativas
diferencias. Mientras que con Binding se utiliza reflexión en tiempo de
ejecución para resolver el enlace a datos, con x:Bind se realiza una
validación en tiempo de ejecución ya que son fuertemente tipados y compilados. Además, ofrece potentes mejoras en el rendimiento.

Crearemos un nuevo proyecto UAP:

Nueva App UAP

Nueva App UAP

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.

En esta ocasión, nuestro objetivo sera crear un listado de casas
donde utilizaremos x:Bind en la plantilla que representará cada elemento
de la lista.

Comenzamos creando la entidad casa dentro de la carpeta Models:

public class House
{
     public string Place { get; set; }
     public string Price { get; set; }
     public string Photo { get; set; }
}

Nuestra interfaz sera muy simple en esta ocasión contando con un sencillo ListView:

<ListView
     ItemsSource="{Binding Houses}" />

El control tiene la fuente de datos enlazada a una propiedad de la ViewModel:

Cargaremos el listado de casas con un método creando datos falsos en local de manera aleatoria:

private void LoadHouses()
{
     _houses = new ObservableCollection<House>();
     Random random = new Random();
     for (int i = 0; i < 100; i++)
     {
          _houses.Add(new House
          {
               Place = Places[random.Next(0, Places.Count)],
               Photo = string.Format("ms-appx:///Assets/{0}.png", random.Next(1, 4)),
               Price = string.Format("${0}", random.Next(10000, 100000).ToString())
          });
     }
}

Y llegamos a la parte más importante, la definición del template de
cada casa, en un diccionario de recursos. Creamos el diccionario de
recursos:

Creamos diccionario de recursos

Creamos diccionario de recursos

Lo registramos en los recursos de la App:

<ResourceDictionary.MergedDictionaries>
     <ResourceDictionary Source="/Styles/AppResourceDictionary.xaml" />
</ResourceDictionary.MergedDictionaries> 

Definimos el template:

<DataTemplate x:Key="HouseTemplate" x:DataType="model:House">
     <Grid Width="200"
           Height="80">
          <Grid.ColumnDefinitions>
               <ColumnDefinition Width="75" />
               <ColumnDefinition Width="*" />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
               <RowDefinition Height="Auto" />
               <RowDefinition Height="Auto" />
           </Grid.RowDefinitions>
           <Image Grid.RowSpan="2"
              Source="{x:Bind Photo}"
              MaxWidth="70"
              MaxHeight="70" />
           <TextBlock Text="{x:Bind Place}"    
                  Grid.Column="1"
                  FontSize="18"/>
           <TextBlock Text="{x:Bind Price}"  
                  Grid.Column="1"  
                  Grid.Row="1"
                  FontSize="12" />
     </Grid>
</DataTemplate>

Utilizamos x:Bind para enlazar cada elemento visual de la plantilla a
la propiedad deseada. Importante resaltar además de compilados, son
fuertemente tipados. Es obligatorio para no tener errores de compilación
indicar el tipo de los datos a los que accedemos por enlace a datos.
Esto lo realizamos utilizando x:DataType. En nuestro ejemplo, la entidad House.

Nuestro ListView quedara:

<ListView
     ItemsSource="{Binding Houses}"
     ItemTemplate="{StaticResource HouseTemplate}" />

Ejecutamos la App y…

Error de compilación

Error de compilación

Diccionario de recursos, el problema

x:Bind o bindings compilados, como indicamos en el nombre deben ser
precompilados. No podemos añadir recursos haciendo uso de bindings
compilados ya sea a nivel de página o de Aplicación directamente;
debemos inicializar e instanciar una clase.

La solución

Debemos añadir una clase parcial, código asociado al recurso para
poder realizar la instanciación del mismo. Creamos la clase parcial:

public partial class AppResourceDictionary
{
     public AppResourceDictionary()
     {
         InitializeComponent();
     }
}

Asociamos la clase parcial con nuestro diccionario de recursos:

x:Class="XBindResources.Resources.AppResourceDictionary"

Modificamos el diccionario de recursos añadiendo la etiqueta x:Class. A continuación, instanciamos el diccionario de recursos:

<ResourceDictionary.MergedDictionaries>
                 
     <!-- Resources -->
     <resources:AppResourceDictionary />      
                 
</ResourceDictionary.MergedDictionaries>

Nos aseguramos que se lanza la llamada a InitializeComponent del mismo.

Si ejecutamos ahora nuestra App:

DataTemplate utilizando x:Bind y x:Phase

DataTemplate utilizando x:Bind y x:Phase

Voila!

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

También podéis acceder al código fuente directamente en GitHub:

Ver GitHub

Más información

[Material] Introducción a Xamarin en dotnetMálaga

El evento

DotNet Málaga, es el grupo de usuarios y
entusiastas de tecnologías Microsoft de Málaga. Con muchas ganas e
ilusión de impulsar fuertemente la comunidad, el networking y la
comnicación entre miembros. El pasado 23 de Septiembre tenía lugar un evento con múltiples sesiones sobre desarrollo Xamarin.

dotNetMálaga

dotNetMálaga

El material

En mi caso, tuve el placer de poder participar el evento con una charla sobre Desarrollo de Apps nativas multiplataforma con Xamarin utilizando MVVMCross. Paso a paso fuimos viendo:

  • Claves de MVVM
  • Introducción a MVVMCross
  • Conceptos de data binding, comandos, etc.
  • Cantidad de código a compartir y técnicas para compartir código.
  • Y más!

 

Evento Xamarin en dotNetMálaga

Evento Xamarin en dotNetMálaga

Tenéis disponible la presentación utilizada a continuación:

En cuanto a la demo técnica realizada, la tenéis disponible en GitHub:

Ver GitHub

Quisiera terminar agradeciendo a Josué Yeray por su participación, a dotNetMálaga por toda la organización, a Plain Concepts por dejarme ir al “sarao” y por supuesto a todos los asistentes. Espero que para todos fuese una tarde divertida y… ¿cuándo repetimos?

Más información

[Xamarin.Forms] Desarrollando para la Microsoft Band

Introducción

El año pasado Microsoft se aventuró en el terrero de wearables con el lanzamiento de Microsoft Band,
una pulsera cuantificadora compatible con Windows Phone, iOS y Android
con posibilidades de monitorización de pasos, ritmo cardiaco, sueño o
metros recorridos además de tener acceso a notificaciones del teléfono
como llamadas, mensajes, correos o notificaciones Twitter por ejemplo.

Xamarin Microsoft Band 01

Además, Microsoft lanzó Microsoft Health, una plataforma en la nube donde controlar todos los datos recogidos relacionados con la salud y la actividad física.

Microsoft Band

Es un wearable con 10 sensores (incluido GPS), pantalla táctil y
batería para hasta 2 días de uso continuo (de media) que se basa en tres
pilares fundamentales:

  1. Salud: Podemos tener información como el número de pasos, pulsaciones, calidad del sueño, ritmo cardiaco, etc.
  2. Productividad: Notificaciones de llamadas perdidas, mensajes, Twitter además de alertas de calendario e incluso Cortana.
  3. Conectividad: App en teléfono en la que obtener más información, históricos, etc.
App móvil

App móvil

Creando proyecto

Para probar todas las opciones de la Microsoft Band vamos a crear un nuevo proyecto desde cero:

Nueva App Xamarin.Forms

Nueva App Xamarin.Forms

Nuestro objetivo sera crear una App Xamarin.Forms destinada a iOS,
Android y Windows Phone que nos permita conectar con una Microsoft Band,
acceder a información de sus sensores, crear tiles, enviar notificaciones, vibraciones e incluso personalizarla.

Permisos

Debemos añadir los siguientes requisitos:

  • Android: Permiso para acceder a Bluetooth:

[assembly: UsesPermission(Android.Manifest.Permission.Bluetooth)]

  • Windows Phone: De igual forma, acceso a Bluetooth:
<DeviceCapability Name="bluetooth.rfcomm">
  <Device Id="any">
    <!-- Used by the Microsoft Band SDK -->
    <Function Type="serviceId:A502CA9A-2BA5-413C-A4E0-13804E47B38F" />
    <!-- Used by the Microsoft Band SDK -->
    <Function Type="serviceId:C742E1A2-6320-5ABC-9643-D206C677E580" />
  </Device>
</m2:DeviceCapability>

Xamarin Microsoft Band SDK

En Xamarin Components y en Nuget tenemos disponible Xamarin Microsoft Band SDK. Es un conjunto de librerías que nos permite extender nuestras Apps móviles integrándolas con la Band. Podremos:

  • Conectar a Band (o Bands)
  • Obtener información de la Band y de los sensores
  • Gestionar tiles y layouts
  • Notificaciones
  • Personalización

Antes de continuar y lanzarnos de lleno a programar, importante
resaltar que la Band ofrece un modelo de extensión, se requiere una App
móvil. Usaremos la Band para obtener información y como pantalla
auxiliar.

Conexión

Para poder interactuar con la Band, lo primero sera…conectar con la misma!. Utilizaremos el siguiente namespace:

using Microsoft.Band.Portable;

Utilizamos el método GetPairedBandsAsync para obtener el listado de Bands disponibles

private async Task LoadBands()        
{            
     Bands = new ObservableCollection<BandDeviceInfo>();            
      
     // Get paired Bands           
     IEnumerable<BandDeviceInfo> bands = await BandClientManager.Instance.GetPairedBandsAsync();
             
     foreach (var band in bands)            
     {               
          Bands.Add(band);    
     }        
}

Mostraremos al usuario el listado de Bands disponible, de modo que,
una vez seleccionada una de ella, utilizaremos la información disponible
en BandDeviceInfo para crear una instancia de BandClient que representará a la Band y nos permitirá trabajar con el resto de acciones (Tiles, notificaciones, etc).

Información de la Band

Una vez seleccionada una Band accedemos a una vista con información
de la misma. Pasamos la Band seleccionada como parámetro en la
navegación:

var bandInfo = navigationContext as BandDeviceInfo;

Podemos extraer información básica como el nombre de la Band de la clase BandDeviceInfo:

BandClient = await BandClientManager.Instance.ConnectAsync(BandInfo);

Podemos obtener más información relacionada con la Band gracias a la instancia de BandClient como la versión de Firmware o de Hardware:

IsConnected = BandClient.IsConnected;
FirmwareVersion = await BandClient.GetFirmwareVersionAsync();
HardwareVersion = await BandClient.GetHardwareVersionAsync();

BandClient representa la Band a la que hemos conectado.

Xamarin Microsoft Band 06Sensores

Entre las posibilidades que tenemos disponibles con la Band, una de
las más interesantes es sin duda obtener información de sensores.
Contamos con la siguiente lista de sensores en la Band:

Sensores

Sensores

Además de acelerómetro, pedómetro y algun sensor del que ya estamos
acostumbrados a encontrar en teléfonos u otros dispositivos, contamos
con sensores muy interesantes como la medición del ritmo cardiaco o UV.

Para trabajar con sensores utilizaremos el siguiente namespace:

using Microsoft.Band.Portable.Sensors;

Utilizando BandClient podemos acceder a SensorManager que nos permitirá acceder a todos los sensores:

var sensorManager = BandClient.SensorManager;

Para trabajar con sensores nos suscribiremos a eventos en los que recibiremos información tanto en valores decimales como Raw.

NOTA: En tiempos prolongados de conexión tiene un impacto negativo en la duración de la batería.

Veamos un ejemplo:

await _sensorManager.Distance.StartReadingsAsync(BandSensorSampleRate.Ms128);
sensorManager.Distance.ReadingChanged += (s, e) =>
{
     TotalDistance = e.SensorReading.TotalDistance;
     var speed = e.SensorReading.Speed;
     var pace = e.SensorReading.Pace;
     var currentmotion = e.SensorReading.CurrentMotion;
};

Nos suscribimos al evento StartReadingsAsync del sensor Distancia para acceder a información como ls velocidad o la distancia total recorrida.

NOTA: Para acceder a la información de alguno de
los sensores, se necesita el consentimiento por parte del usuario. Es
necesario para obtener información del ritmo cardiaco.

Tiles

Los Tiles (baldosas) son uno de los pilares fundamentales de la interfaz de usuario disponible en la plataforma Windows.

Para trabajar con los tiles utilizaremos el namespace:

using Microsoft.Band.Portable.Tiles;

Y la instancia de TileManager:

var tileManager = BandClient.TileManager;

Podemos tener hasta 13 Tiles diferentes e independientes en una
Microsoft Band, podemos obtener el número de “huecos” disponibles que
tenemos en la Band utilizando el método GetRemainingTileCapacityAsync:

// Load Remaining CApacity

RemainingCapacity = await tileManager.GetRemainingTileCapacityAsync();

También podemos obtener un listado de Tiles de nuestra Aplicación utilizados en la Band:

private async Task LoadTiles()
{
     var tiles = await tileManager.GetTilesAsync();
     Tiles = new ObservableCollection<BandTile>(tiles);
}

Utilizamos el método GetTilesAsync para obtener una colección de objetos BandTile.

Creando Tiles

Las Apps pueden crear uno o más tiles. Cada Tile cuenta con GUID e icono que lo identifica.

Tamaño del Icono

Tamaño del Icono

Para crear un nuevo Tile utilizaremos un objeto de tipo BandTile, definiremos un nuevo identificador (Guid) además de la información básica como título, icono, etc:

TileId = Guid.NewGuid();
TileName = "New Tile";
TileIcon = await ResourcesHelper.LoadBandImageFromResourceAsync("Resources/tile.png");
TileBadge = await ResourcesHelper.LoadBandImageFromResourceAsync("Resources/badge.png");

Utilizamos las propiedades anteriores para crear el tile:

var tile = new BandTile(TileId)
{
     Icon = TileIcon,
     Name = TileName,
     SmallIcon = TileBadge,
     IsScreenTimeoutDisabled = DisableScreenTimeout
};

Para añadirlo en la Band, utilizamos el método AddTileAsync disponible en TileManager pasando el objeto BandTile creado:

// Add Tile
await _tileManager.AddTileAsync(tile);

Cada Tile puede contar con hasta 8 páginas. El contenido de cada página es de 245 x 106 píxeles. Las páginas pueden mostrar un mensaje básico un utilizar un Custom Layout. Para crear custom layout utilizaremos un árbol de contenedores y elementos.

Contenedores y Elementos

Contenedores y Elementos

Podemos añadir Custom Layout al Tile añadiendo una colección de objetos PageLayout a la propiedad PageLayouts del tile.

// Tile Custom Layouts
var layouts = CreatePageLayouts();
tile.PageLayouts.AddRange(layouts);

Contamos con varios contenedores que nos permiten organizar los elementos de la página:

  • FlowPanel: Organiza los elementos apilando vertical u horizonalmente.
  • ScrollFlowPanel: Similar al anterior pero añadiendo Scroll.
  • FilledPanel: Rectángulo relleno con un color de fondo.

Además de elementos básicos que nos permiten incluir imágenes, texto, código de barras y botones.

  • TextBlock: Muestra texto.
  • WrappedTextBlock: Similar al anterior pero el texto puede hacer wrapping.
  • Icon: Imágenes.
  • Barcode: Código de barras en diferentes formatos.
  • TextButton: Botón con formato texto.
  • FilledButton: Botón.
new PageLayout {                 
   Root = new ScrollFlowPanel {                      
        Rect = new PageRect(0, 0, 245, 105),                  
        Orientation = FlowPanelOrientation.Vertical,    
        Elements = {
             new TextBlock
             {
                  ElementId = 11,                   
                  Rect = new PageRect(0, 0, 230, 30),                
                  Color = new BandColor(255, 0, 0),             
                  AutoWidth = false,                        
                  HorizontalAlignment = HorizontalAlignment.Center,               
                  VerticalAlignment = VerticalAlignment.Bottom             
             },        
             new Barcode {                   
                  ElementId = 12,          
                  Rect = new PageRect(0, 0, 230, 61),     
                  BarcodeType = BarcodeType.Code39,                     
             },
             new TextBlock
             {
                  ElementId = 13,          
                  Rect = new PageRect(0, 0, 230, 30),                           
                  Color = new BandColor(255, 0, 0),
                  AutoWidth = false,       
                  HorizontalAlignment = HorizontalAlignment.Center,              
                  VerticalAlignment = VerticalAlignment.Bottom                            
             },   
             new Barcode {                      
                  ElementId = 14,
                  Rect = new PageRect(0, 0, 230, 61),
                  BarcodeType = BarcodeType.Pdf417,      
             }          
        }              
   }           
}

Podemos por supuesto también indicar el contenido de textos, botones, códigos de barra etc utilizando el método SetTilePageDataAsync disponible en TileManager:

// Update with page data
var datas = CreatePageDatas();
await _tileManager.SetTilePageDataAsync(tile.Id, datas);

El contenido:

new PageData {       
     PageId = Guid.NewGuid(),      
     PageLayoutIndex = 0,           
     Data = {
          new TextBlockData {               
               ElementId = 11,              
               Text = "Code 39"                 
          },                       
          new BarcodeData {                           
               ElementId = 12,                          
               BarcodeType = BarcodeType.Code39,                
               BarcodeValue = "HELLO"            
          },
          new TextBlockData {                     
              ElementId = 13,                       
              Text = "Pdf 417"                   
          },                        
          new BarcodeData {              
              ElementId = 14,     
              BarcodeType = BarcodeType.Pdf417,           
              BarcodeValue = "0246810"                    
          }                   
     }              
}

La asociación de contenido y elemento la realizamos utilizando el identificador del elemento, ElementId.

Notificaciones

Seleccionado un Tile anclado en la Band, con su correspondiente
identificador, podremos trabajar con notificaciones. Para ello
utilizaremos el siguiente namespace:

using Microsoft.Band.Portable.Notifications;

El objeto NotificationManager será nuestro aliado en esta ocasión.

var notifiactionManager = BandClient.NotificationManager;

Recibimos como parámetro de navegación tanto el identificador del tile como BandClient:

public override void OnAppearing(object navigationContext)
{
     var notificationData = navigationContext as NotificationData;
     if (notificationData != null)
     {
          BandClient = notificationData.BandClient;
          _tile = notificationData.Tile;
     }
 
     _notifiactionManager = BandClient.NotificationManager;
 
     base.OnAppearing(navigationContext);
}

Utilizando NotificationManager podremos enviar notificaciones utilizando los métodos:

  • SendMessageAsync: Envía un mensaje a un Tile de la App con posibilidad de mostrar un diálogo.
  • ShowDialogAsync: Muestra un diálogo en la Band asociado a uno de los Tiles de la App.

Para enviar un mensaje a la Band utilizamos el método SendMessageAsync donde podemos pasar título y contenido:

await notifiactionManager.SendMessageAsync(_tile.Id, Title, Body, DateTime.Now);

Podemos indicar facilmente con otro parámetro que deseamos mostrar un diálogo:

await notifiactionManager.SendMessageAsync(_tile.Id, Title, Body, DateTime.Now, true);

Utilizando el método ShowDialogAsync podemos mostrar un diálogo directo en la Band:

await notifiactionManager.ShowDialogAsync(_tile.Id, Title, Body);

Sencillo, ¿verdad?

Vibración

Continuamos con otras opciones disponibles con las que podemos
interactuar con la Band. Una forma sencilla pero muy potente para
notificar al usuario es enviar notificaciones hápticas o vibraciones.
Tenemos una enumeración de tipo VibrationType con las siguientes opciones:

  • NotificationOneTone
  • NotificationTwoTone
  • NotificationAlarm
  • NotificationTimer
  • OneToneHigh
  • TwoToneHigh
  • ThreeToneHigh
  • RampUp
  • RampDown
public ObservableCollection<string> GetVibrationTypes()   
{          
     var names = Enum.GetNames(typeof(VibrationType));     
     var split = names.Select(n =>                
          string.Concat(n.ToCharArray().Select(c =>                 
          char.IsUpper(c) ? " " + c : c.ToString())));
            
     return new ObservableCollection<string>(split.ToList());
}

Utilizamos el método VibrateAync disponible en NotificationManager indicando el tipo de la vibración:

await notifiactionManager.VibrateAsync((VibrationType)_vibrationIndex);

Personalización

Para trabajar con notificaciones utilizaremos el siguiente namespace:

using Microsoft.Band.Portable.Personalization;

Y PersonalizationManager:

var personalizationManager = BandClient.PersonalizationManager;

Podremos:

  • Cambiar imagen “Me Tile”
  • Modificar colores del tema

La imagen “Me Tile”:

Me Tile

Me Tile

Es una imagen de 310 x 102 píxeles mostrada en la pantalla principal
de la Band. Podemos establecer la imagen utilizando el método SetMeTileImageAsync:

MeTileImage = await ResourcesHelper.LoadBandImageFromResourceAsync("Resources/metile.png");
await personalizationManager.SetMeTileImageAsync(MeTileImage);

También podemos editar el tema de la Band basado en un conjunto de colores:

Colores del tema

Colores del tema

Base = new BandColor(10, 110, 20);
HighContrast = new BandColor(20, 120, 30);
Highlight = new BandColor(30, 130, 40);
Lowlight = new BandColor(40, 140, 50);
Muted = new BandColor(50, 150, 60);
SecondaryText = new BandColor(60, 160, 70);

Estableciendo el tema utilizando el método SetThemeAsync pasándole un objeto de tipo BandTheme que contiene todo el conjunto de colores usados en diferentes estados:

await _personalizationManager.SetThemeAsync(new BandTheme
{
     Base = Base,
     HighContrast = HighContrast,
     Highlight = Highlight,
     Lowlight = Lowlight,
     Muted = Muted,
     SecondaryText = SecondaryText
});

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

También tenéis el código fuente disponible e GitHub:

Ver GitHub

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

One more thing

WebTiles

Recientemente el equipo de Microsoft Band liberaron los Web Tiles.
Los Web Tiles son una forma fácil y sencilla de poder crear nuevos
Tiles que muestren información desde una URL que devuelva información en
JSON, RSS o ATOM feed sin necesidad de grandes conocimientos ni
programación.

Para ello, accederemos al siguiente enlace y completaremos el asistente paso a paso.

Microsoft Health APIs

Es una plataforma abierta de APIs Rest que nos permite a los
desarrolladores acceder a información de sensores, históricos y otras
opciones para poder crear Apps de salud y deporte de alta calidad.

Más información

[Tips and Tricks] Windows 10: Mostrar botón atrás en la TitleBar

Introducción

Casi cualquier aplicación que realices tendrá más de una página. Por lo que es vital saber como navegar entre ellas. Ya vimos paso a paso como navegar entre páginas en este otro artículo. Sin embargo, Windows 10 ha llegado como la culminación en el viaje hacia la convergencia en el desarrollo entre plataformas Windows. Ahora hablamos de Apps Universales
escritas una única vez con un código común tanto para la lógica de
negocio como para la interfaz de usuario. Además, generamos un único
paquete que mantendrá una interfaz consistente y familiar para el
usuario pero adaptada a cada plataforma. Podemos crear apps que
funcionen en todo tipo de dispositivos como teléfonos, tabletas,
portátiles, dispositivos IoT, Surface Hub e incluso HoloLens.
Ante
tal cantidad de dispositivos disponibles tenemos peculiaridades
exclusivas en algunos de ellos. Un de ellas es el botón virtual (en
pantalla) para volver atrás necesario en alguna familia de dispositivo.
Cuando permitimos navegar también debemos permitir volver atrás…

Navegación

Creamos un nuevo proyecto:

Nueva App UAP

Nueva App UAP

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.

En la carpeta Views añadiremos nuestras páginas. En nuestro ejemplo, tendremos dos páginas:

  • FirstView
  • SecondView

Añadimos en la primera vista (FirstView) dos botones que permita navegar a la segunda vista sin pasar y pasándo parámetro:

<Grid
     Background="LightBlue">
     <StackPanel
          HorizontalAlignment="Center"
      VerticalAlignment="Center">
      <Button
        Content="Go to Second View"
        Command="{Binding GoToSecondCommand}" />
      <Button
        Content="Pass parameter"
        Command="{Binding ParameterCommand}"
        Margin="0, 10"/>
     </StackPanel>
</Grid>

El resultado visual:

Vista principal

Vista principal

Para permitir navegar a la segunda vista, necesitamos definir dos
comandos (uno navegará sin pasar parámetro y otro pasándolo) en la ViewModel:

public class FirstViewModel : ViewModelBase
{
        private ICommand _goToSecondCommand;
        private ICommand _parameterCommand;
  
    public override Task OnNavigatedFrom(NavigationEventArgs args)
    {
        return null;
    }
  
    public override Task OnNavigatedTo(NavigationEventArgs args)
    {
        return null;
    }
  
    public ICommand GoToSecondCommand
    {
        get { return _goToSecondCommand = _goToSecondCommand ?? new DelegateCommand(GoToSecondCommandExecute); }
    }
  
    public ICommand ParameterCommand
    {
        get { return _parameterCommand = _parameterCommand ?? new DelegateCommand(ParameterCommandExecute); }
    }
  
    private void GoToSecondCommandExecute()
    {
        AppFrame.Navigate(typeof(SecondView));
    }
  
    private void ParameterCommandExecute()
    {
        var rnd = new Random();
        AppFrame.Navigate(typeof(SecondView), rnd.Next(1, 100));
    }
}

Recordamos que el control Frame hospeda controles Page
y tiene un historial de navegación que se puede utilizar para ir hacia
atrás y hacia adelante por las páginas que ya visitaste. Tras obtener el
Frame correspondiente, utilizamos el método Navigate para realizar la navegación a otra página. Tenemos dos sobrescrituras del método Navigate:

  • Navigate(TypeName). Provoca que el Frame cargue el contenido especificado por el tipo pasado como parámetro.
  • Navigate(TypeName, Object).
    En este caso, además de indicar el tipo del contenido a cargar (primer
    parámetro), podemos pasar un parámetro a la página que se navega(segundo
    parámetro).

En nuestro ejemplo hemos utilizado la segunda sobrescritura del método pasando un parámetro.

Nuestra segunda página sera similar a la primera:

<Grid
     Background="LightGreen">
     <StackPanel
         HorizontalAlignment="Center"                    
         VerticalAlignment="Center">
         <Button
             Content="Go Back"
             Command="{Binding BackCommand}" />
         <TextBlock
             Text="{Binding Parameter}"
             Visibility="{Binding Parameter, Converter={StaticResource IntToVisibilityConverter}}"
             FontSize="48" />
     </StackPanel>
</Grid>

Contará con su propia viewmodel:

public class SecondViewModel : ViewModelBase
{
    // Variables
    private int _parameter;
  
    // Commands
    private ICommand _backCommand;
  
    public override Task OnNavigatedFrom(NavigationEventArgs args)
    {
        return null;
    }
  
    public override Task OnNavigatedTo(NavigationEventArgs args)
    {
            if (args.Parameter != null)
        {
            Parameter = Convert.ToInt32(args.Parameter);
                }
  
        return null;
    }
  
    public int Parameter
    {
        get { return _parameter; }
        set
        {
            _parameter = value;
            RaisePropertyChanged();
        }
    }
  
    public ICommand BackCommand
    {
        get { return _backCommand = _backCommand ?? new DelegateCommand(BackCommandExecute); }
    }
  
    private void BackCommandExecute()
    {
        if (AppFrame.CanGoBack)
            AppFrame.GoBack();
    }
}

Utilizamos el método GoBack del
Frame que navega al elemento más inmediato del historial de navegación,
la página anterior. Por otro lado, en caso de recibir parámetro, lo
asignamos a una propiedad bindeada en la vista. En nuestro ejemplo
pasamos un valor aleatorio entero entre 1 y 100.

Añadiendo el botón volver atrás en la Title Bar

Todas nuevas ViewModels derivan de la ViewModelBase:

public abstract class ViewModelBase : INotifyPropertyChanged
{
     public event PropertyChangedEventHandler PropertyChanged;
 
     public virtual Task OnNavigatedFrom(NavigationEventArgs args)
     {
         return null;
     }
 
     public virtual Task OnNavigatedTo(NavigationEventArgs args)
     {
         return null;
     }
 
     public void RaisePropertyChanged([CallerMemberName]string propertyName = "")
     {
         var Handler = PropertyChanged;
         if (Handler != null)
            Handler(this, new PropertyChangedEventArgs(propertyName));
     }
}

Cada vez que entramos a una página se lanza el evento OnNavigatedTo. En este método utilizamos la propiedad AppViewBackButtonVisibility del objecto SystemNavigationManager asociado a la ventana actual:

Frame rootFrame = Window.Current.Content as Frame;
 
if (rootFrame.CanGoBack)
     SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
else
     SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Collapsed;

Si podemos navegar atrás, mostramos el botón volver atrás en la Title Bar. Nos faltaría gestionar el evento lanzado al pulsar el botón utilizando el evento BackRequested:

SystemNavigationManager.GetForCurrentView().BackRequested += (sender, args) =>
{
     if (rootFrame.CanGoBack)
          rootFrame.GoBack();
};

NOTA: Recordad, no sería necesario este proceso en todas las familias de dispositivos soportados en Windows 10.

El resultado:

Botón volver en la Title Bar

Botón volver en la Title Bar

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

También tenéis el código fuente disponible e GitHub:

Ver GitHub

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

Más información

[Material Evento SVQXDG] Programando para Apple Watch, Microsoft Band y Google Wear con Xamarin

El evento

El pasado Miércoles 16 de Septiembre tenía lugar el primer evento del grupo SVQXDG, grupo de desarrolladores Xamarin de Sevilla en el workINcompany.  Un evento con múltiples charlas todas enfocadas al desarrollo de los principales wearables utilizando Xamarin.

El material

En mi caso, tuve el placer de poder participar el evento con una charla sobre Desarrollo para la Microsoft Band con Xamarin. Paso a paso fuimos viendo como:

  • Encontrar Bands disponibles
  • Conectar con una Band
  • Obtener toda su información básica
  • Trabajar con sensores
  • Trabajar con tiles, obteniendo información
  • Crear tiles, custom layouts, distintos contendores, páginas, etc.
  • Envío de notificaciones y vibraciones
  • Personalización
  • Y más!

Tenéis disponible la presentación utilizada a continuación:

En cuanto a la demo técnica realizada, la tenéis disponible en GitHub:

Ver GitHub

Quisiera terminar agradeciendo a Josué Yeray y a Marcos Cobeña por su participación, a workINCompany por la sala, a Plain Concepts por el patrocinio y por supuesto a todos los asistentes. Espero que para todos fuese una tarde divertida y… ¿cuándo repetimos?

Más información

[Evento] Introducción a Xamarin en dotnetMálaga

El evento

DotNet Málaga, es el grupo de usuarios y
entusiastas de tecnologías Microsoft de Málaga. Con muchas ganas e
ilusión de impulsar fuertemente la comunidad, el networking y la
comnicación entre miembros. Con varios eventos ya organizados para los
próximos meses, este mes de Septiembre tendra lugar un evento sobre
desarrollo de Apps móviles multiplataforma con Xamarin.

La agenda

La agenda del evento será la siguiente:

  • 17:00h – 17:05h: Bienvenida.
  • 17:05h – 18:05h: Comenzamos realizando una introducción a Xamarin y Xamarin Forms.
    Xamarin.Forms nos permite crear aplicaciones para las tres plataformas
    móviles principales: iOS, Android y Windows Phone. Además de compartir
    la lógica de la aplicación, Xamarin.Forms nos permite reutilizar el
    código de interfaz de usuario, escribiéndolo con XAML o con C# y
    renderizándolo a código de interfaz nativa en tiempo de ejecución.
    Veremos conceptos básicos y la estructura de proyectos en Xamarin Forms
    analizando posibilidades, cantidad de código compartido, etc.
  • 18:05h – 19:05h: Continuaremos con una sesión de desarrollo con Xamarin Classic.
    Xamarin nos permite compartir código de nuestras aplicaciones iOS,
    Android y Windows usando un lenguaje común que es C# y compartiendo la
    lógica común a las distintas plataformas desarrollando la interfaz de
    usuario en este caso con código nativo de cada plataforma. En esta
    sesión veremos la estructura de proyectos con Xamarin Classic utilizando
    MVVMCross, cantidad de código a compartir, etc.

Tendremos dos ponentes, Josué Yeray y un servidor
dedicados a la primera y segunda sesión respectivamente. Ambos
desarrolladores móviles, Microsoft MVPs en desarrollo Windows y
apasionados de la comunidad.

Fecha

El evento tendrá lugar el próximo Miércoles, 23 de Septiembre de 17:00h a 19:00h. Tendremos dos sesiones de 2:00 horas de duración en total.

Lugar

Tendrá lugar en DataControl Formación. Tenéis la información exacta del lugar a continuación:

C/ Casas de Campos 7, Málaga

¿Te apuntas?

Más información

[Evento SVQXDG] Programando para Apple Watch, Microsoft Band y Google Wear con Xamarin

El evento

En Sevilla, existen empresas y desarrolladores con un enorme talento
utilizando Xamarin para sus desarrollos de Apps móviles. Con este crisol
nació SVQXDG, o lo que es lo mismo, grupo de desarrolladores Xamarin de Sevilla. Es un grupo de usuario donde se busca tener un punto habitual de reunión para ayudar, compartir y aprender entre todos.

SVQXDG

SVQXDG

Tras un periodo veraniego de merecido descanso, el grupo vuelve con fuerza organizando un evento completo con múltiples sesiones abordando de fondo el desarrollo para  wearables.

La agenda

  • 18:30h -18:35h: Bienvenida. Recepción de asistentes, sesión introductoria donde repasar la agenda y otros detalles.
  • 18:35h – 19:20h: Desarrollo para el Apple Watch con Xamarin. De la mano de Josué Yeray tendremos una introducción al Watch Kit, estructura, diseño, controles y mucho más!
  • 19:20h – 19:25h: Descanso.
  • 19:25h – 20:10h: Posibilidades con Microsoft Band utilizando Xamarin. En esta sesión, con un servidor,
    veremos como crear Apps multiplataforma con Xamarin accediendo a la
    Microsoft Band, acceso a sensores, creación de Tiles, notificaciones,
    etc.
  • 20:10h – 20:15h: Descanso.
  • 20:15h – 21:00h: Introducción al desarrollo para Google Wear. De la mano de Marcos Cobeña tendremos una sesión donde repasaremos todo lo necesario para desarrollar para Google Wear.

El lugar

Tendrá lugar en el workINcompany. Tenéis la información exacta del lugar a continuación:

Calle Rioja 13 2A, Sevilla

Fecha

El evento tendrá lugar el próximo Miércoles, 16 de Septiembre de 18:30h a 21:00h. Tendremos tres sesiones de  45 minutos de duración cada una contando con 5 minutos de descanso entre sesiones.

¿Te apuntas?

Más información

[Windows 10] Trabajando con múltiples ventanas

Introducción

Hay ocasiones en las que contar con más de una ventana en la misma App
añade unas posibilidades increíbles mejorando exponencialmente el uso y
funcionalidad de la misma. Para centrarnos en lo que estamos hablando,
pongamos un ejemplo. El uso de PowerPoint proyectando una presentación.
La audiencia ve la presentación a pantalla completa mientras en otra
pantalla el ponente puede ver más información con más acciones (página
actual, siguiente, número de páginas, etc).

De igual forma, se nos pueden ocurrir cientos de escenarios donde
permitir tener varias ventanas, aprovechar múltiples pantallas, etc. En
este artículo vamos a aprender como permitir abrir más de una ventana de
la misma App y los detalles involucrados en el proceso.

NOTA: En Windows 8.1 ya teníamos la posibilidad de realizar esta acción. Ejemplo de App que hacía uso de la misma, la App de correo.

Múltiples ventanas en App de correo (Windows 8.1)

Múltiples ventanas en App de correo (Windows 8.1)

Múltiples ventanas

Conceptos básicos

Antes de “arrancar” vamos a repasar algunos conceptos
básicos. Cuando abrimos múltiples ventanas en la misma App, cada ventana
se ejecuta en un hilo y contexto diferente. No por ello serán bloques
aislados, podemos permitir la comunicación utilizando Dispatcher.BeginInvoke.

NOTA: Por supuesto también podemos utilizar datos almacenados en el almacenamiento aislado de la App, Roaming, etc.

Comenzamos!

Crearemos un nuevo proyecto UAP:

Nueva App UAP

Nueva App UAP

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. Vamos a permitir crear una vista secundaria desde nuestra vista principal.

Comenzamos definiendo la vista principal:

<StackPanel
     HorizontalAlignment="Center"
     VerticalAlignment="Center">
     <Button
          Content="Create Secondary View"/>
</StackPanel>

Muy simple, ¿cierto?. Tendremos un único botón que nos permitirá crear
la ventana secundaria. Para que el botón ejecute la acción necesitaremos
definir el comando necesario en la ViewModel:

private ICommand _createSecondaryViewCommand;
 
public ICommand CreateSecondaryViewCommand
{
     get { return _createSecondaryViewCommand = _createSecondaryViewCommand ?? new DelegateCommand(CreateSecondaryViewCommandExecute); }
}
 
private async void CreateSecondaryViewCommandExecute()
{
 
}

Bindeamos el comando con el botón:

<StackPanel
     HorizontalAlignment="Center"
     VerticalAlignment="Center">
     <Button
          Content="Create Secondary View"
          Command="{Binding CreateSecondaryViewCommand}"/>
</StackPanel>

El resultado por ahora es:

Primera ventana

Primera ventana

Creando ventana secundaria

Para trabajar con ventanas utilizaremos para diferentes acciones
(switch, cerrar, etc) el identificador de la ventana. Podemos obtener el
identificador de una ventana utilizando el método GetApplicationViewIdForWindow disponible dentro de ApplicationView.

var _mainViewId = ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread());

La línea anterior nos permite obtener el identificador del CoreWindow específico correspondiente a nuestra vista y ventana principal.

Para abrir la nueva ventana lo primero que debemos hacer es… crearla:

var newView = CoreApplication.CreateNewView();

Utilizamos el método CreateNewView disponible en CoreApplication.
Esta línea crea un nuevo hilo y una nueva ventana en ese mismo hilo. La
ventana creada por supuesto no esta visible. La ventana visible es la
principal, creada en el arranque de la App. Es importante tener en
cuenta que, todos los eventos de activación se lanzarán en el hilo
principal, es decir, la ventana principal. Si se cierra la ventana
principal o su hilo de ejecución termina (sea cual sea el motivo) la App
se cerarrá.

Contenido de la ventana secundaria

Llegados a este punto, tenemos nuestra vista principal, pulsamos un
botón y creamos otro hilo donde creamos la ventana secundaria pero…¿que muestra?

Nuestro siguiente paso será indicar el contenido de la ventana secundaria:

var newView = CoreApplication.CreateNewView();
int newViewId = 0;
 
await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
     var frame = new Frame();
     frame.Navigate(typeof(SecondaryView), null);
     Window.Current.Content = frame;
     Window.Current.Activate();
 
     newViewId = ApplicationView.GetForCurrentView().Id;
});

Navegamos a una nueva vista e importante, llamamos a la activación (necesario en Windows 10).

NOTA: Resaltar que utilizamos Dispatcher.RunAsync para comunicarnos con la vista, recordar que se usa un hilo diferente.

Mostrando la vista secundaria

Ya tenemos creada nuestra vista secundaria y hasta tiene contenido, nos falta mostrarla. Utilizaremos el método TryShowAsStandaloneAsync disponible en la clase ApplicationViewSwitcher:

var viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(
                newViewId,
                ViewSizePreference.Default,
                ApplicationView.GetForCurrentView().Id,
                ViewSizePreference.Default);

Le pasamos el identificador de la nueva ventana y muestra la ventana secundaria junto a la ventana principal.

Definición de la vista secundaria

Hemos mostrado una vista secundaria pero nos falta ver su definición:

<StackPanel
     HorizontalAlignment="Center"
     VerticalAlignment="Center">
     <Button
          Content="Switch to Main View"/>
     <Button
          Content="Switch to Main View and Hide"/>
</StackPanel>

Añadiremos dos botones. El primero de ellos nos pasará de la ventana
secundaria a la pantalla principal (cambiará la ventana activa)
manteniendo ambas ventanas mientras que el segundo botón realizará lo
mismo pero cerrando la ventana secundaria programáticamente.

Añadimos los comandos para los botones en la ViewModel:

private ICommand _switchViewCommand;
private ICommand _hideViewCommand;
 
public ICommand SwitchViewCommand
{
     get { return _switchViewCommand = _switchViewCommand ?? new DelegateCommand(SwitchViewCommandExecute); }
}
 
public ICommand HideViewCommand
{
     get { return _hideViewCommand = _hideViewCommand ?? new DelegateCommand(HideViewCommandExecute); }
}
 
private void SwitchViewCommandExecute()
{
 
}
 
private void HideViewCommandExecute()
{
 
}

Bindeamos los comandos correspondientes:

<StackPanel
     HorizontalAlignment="Center"
     VerticalAlignment="Center">
     <Button
          Content="Switch to Main View"
          Command="{Binding SwitchViewCommand}"/>
     <Button
          Content="Switch to Main View and Hide"
          Command="{Binding HideViewCommand}"/>
</StackPanel>

El resultado tras abrir la ventana secundaria:

Ventana secundaria

Ventana secundaria

View Switching

Nos falta por ver un detalle muy importante, el intercambio y gestión entre ventanas.

para hacer el intercambio de una ventana a otra utilizaremos el método SwitchAsync disponible en la clase ApplicationViewSwitcher:

await ApplicationViewSwitcher.SwitchAsync(App.MainViewId);

A la llamada le pasamos como parámetro el identificador de la ventana
que deseamos que reemplace a la actual, en nuestro ejemplo, la ventana
principal.

De igual forma, además de poder hacer el intercambio de la ventana, podemos cerrar una secundaria:

await ApplicationViewSwitcher.SwitchAsync(App.MainViewId,
                ApplicationView.GetForCurrentView().Id,
                ApplicationViewSwitchingOptions.ConsolidateViews);

Aprovechamos otra sobrecarga del método SwitchAsync para
pasar además del identificador de la ventana a la que deseamos hacer el
switch, el identificador de la ventana que deseamos cerrar y el modo en
el que se realiza el intercambio entre ventanas. Para indicar el modo
utilizamos un parámetro de tipo ApplicationViewSwitchingOptions. Es una enumeración con los siguientes valores:

  • Default: Transición estándar entre ventanas.
  • SkipAnimation: Transición inmediata entre ventanas.
  • ConsolidateViews: Cierra la ventana, la quita del listado de usadas recientemente y vuelve a la ventana a la que se realiza el cambio.

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

También tenéis el código fuente disponible e GitHub:

Ver GitHub

Recordad que podéis dejar cualquier comentario, sugerencia o duda en los comentarios.

Más información