[Evento Online] Bienvenidos al desarrollo holográfico!

HololensIntroducción

Desde que Hololens apareció en nuestro horizonte, aparición a aparición, demo tras demo ibamos viendo posibilidades y un nuevo abanico de opciones abiertas de cara al desarrollo. Más tarde conocimos características, se liberó el SDK y comenzaron las primeras hornadas de dispositivos llegando a desarrolladores.

Hololens

Hololens

Ahora, con ellas a nuestra alcance, tras probar a fondo el SDK, emulador, Unity e incluso con la liberación de la versión inicial de la extensión de Hololens de parte de Wave Engine, ¿algo mejor que verlo y probarlo todo a fondo?.

El evento

¿Quieres ver que es lo más nuevo de Microsoft en dispositivos de interacción? ¿Qué es un gaze o bloom? En esta sesión comenzaremos con un unboxing de HoloLens, continuaremos con un análisis de características y apps disponibles y terminaremos viendo como desarrollar apps para HoloLens, adaptar apps UWP para HoloLens y como acceder al dispositivo para controlarlo por voz, etc.

Estrenamos nuevo formato en CartujaDotNet habilitando eventos online para ayudar y contribuir a cualquier miembro de la comunidad. El evento será el próximo Viernes, 03 de Junio.

  • 19:00 en España
  • 13:00 en Colombia
  • 12:00 en México Centro
  • 13:30 en Venezuela
  • 15:00 en Chile continental

¿Te apuntas?

Más información

Anuncios

[Material CartujaDotNet] Sevilla Windows REBUILD

El evento

El pasado 21 de Abril, desde el grupo CartujaDotNet, grupo de usuarios .NET de Sevilla, organizábamos el Sevilla Windows REBUILD. Un evento donde recopilamos algunas de las principales novedades a nivel de desarrollo en la plataforma Universal Windows además de tener momentos para el networking y algun que otro detalle con los asistentes.

Novedades desarrollo UWP presentadas en el BUILD

Novedades desarrollo UWP presentadas en el BUILD

El material

Pude participar en el evento con múltiples sesiones. Tras una breve introducción a la agenda del evento comenzamos viendo las últimas novedades introducidas en Visual Studio (VS 2015 Update 2 y VS 15) destinadas para el desarrollo de UWP. Novedades en el editor XAML o Editar y Continuar en XAML:

Continuamos utilizando Desktop App Converter (aka Project Centennial) viendo como convertir una App Win32 en UWP.

En la siguiente sesión nos centramos en el desarrollo de aplicaciones UWP para Xbox One. Vimos desde como activar cualquier Xbox One para el modo desarrollador hasta como adaptar nuestras aplicaciones para ofrecer la mejor experiencia posible (gestión del gamepad, foco, TV safe area o sonidos).

En cuanto a las demos técnicas realizadas, las tenéis disponible en GitHub:

Ver GitHub

Quisiera terminar añadiendo algunos agradecimientos a Josué Yeray por participar junto a un servidor en las sesiones y por supuesto, muchas gracias a todos los asistentes.

Más información

Desktop App Converter, de Win32 a UWP

BridgeIntroducción

Llegar a Windows es mucho más sencillo que nunca. Si tienes una web, si tienes una App en iOS e incluso si partes de una App Win32, existen nuevas opciones destinadas a facilitar la llegada de esas Apps a Windows de la forma más sencilla posible. Si, hablamos de los Bridges presentados en el //BUILD del año 2015.

Un año después, en el marco del //BUILD 2016 se ha profundizado, conocido e incluso tenemos acceso a Project Centennial renombrado como Desktop App Converter, destinado a convertir Apps basadas en .NET y Win32 como Apps UWP. Además, permite el acceso a servicios o APIs UWP.

//BUILD 2016

//BUILD 2016

¿Quieres saber más el respecto?

En este artículo vamos a convertir una App Win32 a UWP utilizando Desktop App Converter paso a paso, desde la instalación de la herramienta hasta tener el paquete preparado, firmado y listo para distribución.

¿Qué es Desktop App Converter?

Herramienta disponible (pre-release) que nos permite llevar las aplicaciones de escritorio NET 4.6.1 o Win32 a la plataforma universal Windows (UWP). Basado en una línea de comandos, que se puede ejecutar de forma desatendida o silenciosa, crea un paquete appx que puede ser instalado mediante el comando Add-AppxPackage de PowerShell.

Desktop App Converter

Desktop App Converter

El convertidor utiliza una imagen limpia del sistema (disponible junto al convertidor) para utilizar una versión totalmente limpia del mismo y capturar cualquier entrada de registro, rutas de archivos, etc. y empaquetarlo todo en un paquete appx con su archivo de manifiesto correspondiente.

Las principales características son:

  • Permite convertir Apps Win32 a UWP.
  • Mantener y reutilizar la investigación y desarrollo invertida en la aplicación Win32.
  • Poder añadir y utilizar APIs UWP (Tiles, etc).
  • Utilizar la Windows Store y también poder monetizar la aplicación utilizando esta vía.

Preparación del entorno

Comenzamos descargando y preparando la herramienta pero antes incluso de descarga, repasemos los prerequisitos de hardware y software. Necesitamos una máquina de desarrollo con:

  • Procesador de 64 bits
  • Hardware-assisted virtualization
  • Second Level Address Translation (SLAT)

Mientras que a nivel de software debemos tener la versión 10.0.14316.0 o superior de Windows 10 Preview.

NOTA: Debemos tener la versión Enterprise de Windows para poder utilizar la herramienta. De momento, la versión pre-release disponible no funciona en la versión Pro.

Una vez revisados (y cumplidos) los requisitos necesarios realizamos la descarga de la herramienta. Podemos descargar Desktop App Converter desde el siguiente enlace.

Descargar Desktop App Converter

Descargar Desktop App Converter

Será necesario descargar:

  • DesktopAppConverter.zip
  • BaseImage-14316.wim

Tras extraer el archivo zip, estamos preparados para comenzar a preparar el entorno.

Comenzamos abriendo una ventana de PowerShell con privilegios de administrador.

Comenzamos modificando las preferencias de las políticas de ejecución de PowerShell evitando bloqueos o mensajes de alerta.

Set-ExecutionPolicy bypass
Set-ExecutionPolicy bypass

Set-ExecutionPolicy bypass

A continuación realizamos el setup de la herramienta con la siguiente línea:

.\DesktopAppConverter.ps1 -Setup -BaseImage .\BaseImage-14316.wim

NOTA: Debemos asegurarnos de navegar a la carpeta correspondiente donde hemos descomprimido la herramienta. Dependiendo de la elegida, la línea anterior puede cambiar ligeramente.

Llegados a este punto tenemos todo lo necesario para comenzar a utilizar la herramienta, es decir, para convertir Apps Win32 a UWP.

De Win32 a UWP!

El uso de la herramienta, como hemos comentado previamente, se realiza vía línea de comandos contando con gran cantidad de opciones:

DesktopAppConverter.ps1
-ExpandedBaseImage <String>
-Installer <String> [-InstallerArguments <String>] [-InstallerValidExitCodes <Int32>]
-Destination <String>
-PackageName <String>
-Publisher <String>
-Version <Version>
[-AppExecutable <String>]
[-AppFileTypes <String>]
[-AppId <String>]
[-AppDisplayName <String>]
[-AppDescription <String>]
[-PackageDisplayName <String>]
[-PackagePublisherDisplayName <String>]
[-MakeAppx]
[-NatSubnetPrefix <String>]
[-LogFile <String>]
[<CommonParameters>]

Tendremos parámetros obligatorios:

  • -ExpandedBaseImage: Ruta absoluta a la imagen base.
  • -Installer: Ruta a la aplicación Win32.
  • -InstallerArguments: Lista de parámetros separados por comas. Este parámetro es opcional si usamos un msi. Nos permite configurar sistema de logs, instalación silenciosa, etc.
  • -Destination: Ruta del paquete appx resultante.
  • -PackageName: El nombre que identifica el paquete.
  • -Publisher: Nombre del publicador incluido en el paquete.
  • -Version: Versión del paquete.

y otros opciones que pueden sernos de utilidad según el caso (por ejemplo, modo verboso). Podemos acceder vía línea de comandos a la ayuda de la herramienta en todo momento:

get-help .\DesktopAppConverter.ps1 -detailed

De modo que, convertir una aplicación Win32 llamada App.exe a una App UWP llamada “App” con versión 0.0.0.1 y publicador jsuarez serían tan sencillo como:

.\DesktopAppConverter.ps1 -Expanded C:\ProgramData\Microsoft\Windows\Images\BaseImage-14316 
–Installer C:\DesktopAppConverter\App.exe -InstallerArguments "/S" -Destination "C:\DesktopAppConverter\Output" 
-PackageName "App" -Publisher "CN=jsuarez" -Version 0.0.0.1 -MakeAppx -Verbose

Ejecutando el script en modo verboso en todo momento tenemos feedback del proceso (repaso de requisitos, conversión de rutas, registro,  preparación del manifiesto, etc):

Proceso de conversión

Proceso de conversión

Una vez terminado el proceso, en la carpeta de salida:

El resultado

El resultado

NOTA: Los paquetes generados por ahora sólo se pueden desplegar en sistemas x64.

Firmar el paquete

Para distribuir el paquete utilizaremos el comando Add-AppxPackage disponible en PowerShell. Para poder distribuirlo, el paquete debe estar firmado.

Para firmar el paquete, comenzaremos creando un certificado temporal utilizando la herramienta MakeCert. Abrimos una nueva ventana del símbolo del sistema de VS:

Símbolo del sistema de VS

Símbolo del sistema de VS

Bastará con escribir:

MakeCert.exe -r -h 0 -n "CN=jsuarez" -eku 1.3.6.1.5.5.7.3.3 -pe -sv myCert.pvk myCert.cer

Nos pedirá una contraseña:

Creando certificado

Creando certificado

A continuación, utilizamos Pvk2Pfx para generar el archivo pfx a utilizar para firmar el paquete:

pvk2pfx.exe -pvk myCert.pvk -spc myCert.cer -pfx myCert.pfx

Por último, utilizando Signtool para firmar el paquete:

signtool.exe sign -f myCert.pfx -fd SHA256 -v "C:\DesktopAppConverter\Output\App.appx"

Todo listo!. Ahora tenemos nuestra App Win32 conertida a UWP y lista para su distribución.

Despliegue

Utilizaremos la línea de comandos Add-AppxPackage para instalar la App. Sin embargo, obtendremos un error si en la máquina no tenemos importado el certificado con el que se firmó la App.

Para importar el certificado:

  1. Clic derecho sobre el paquete de la App, Propiedades -> Firmas digitales.
  2. Seleccionamos la firma, ver detalles y a continuación, ver certificado.
  3. Instalar certificado.
  4. Elegimos la opción equipo local y el contenedor de personas de confianza.
  5. Completamos.
Instalando certificado

Instalando certificado

Todo listo!. Ahora si, podemos ejecutar la línea:

Add-AppxPackages "C:\DesktopAppConverter\Output\App.appx"

La App se instalará!

Otros detalles

Desktop App Converter por defecto captura información relacionada con su uso y se la envía a Microsoft con el objetivo de mejora continua. Si deseamos modificar el comportamiento podemos añadir el siguiente valor del registro:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DesktopAppConverter

Añadiremos el valor DisableTelemetry con DWORD establecido a 1 para deshabilitar el envío de información. Para volver a habilitar bastará con establecer el valor a 0 o bien, eliminar la entrada del registro.

¿Y ahora qué?

Llegados a este punto conocemos la herramienta, sus posibilidades y podemos comenzar a sacarle partido. Sin embargo, aún podemos llegar mucho más lejos. Podemos hacer uso desde la aplicación de de APIs UWP como:

  • Live Tiles
  • Cortana
  • Notificaciones
  • Etc

Podemos migrar código, utilizar AppServices y mucho más!. En próximos artículos continuaremos profundizando en la herramienta viendo coo realizar alguna de estas acciones. Os espero en el próximo!

Mientras tanto, ¿cuáles son vuestras experiencias?, ¿qué os parece Desktop App Converter?. Recordar que cualquier tipo de duda, sugerencia o comentario la podéis dejar en los comentarios de la entrada.

Más información

[Evento CartujaDotNet] Windows //REBUILD

dateEl evento

Tras un //BUILD 2016 repleto de novedades, ¿algo mejor que tener varias sesiones con las novedades más destacadas relacionadas con el desarrollo en Windows?.

//BUILD 2016

//BUILD 2016

Desde CartujaDotNet estamos convencidos que tendremos una divertida tarde con por supuesto sesiones técnicas, pero además, regalos, networking y otras grandes sorpresas.

La agenda

Contaremos con la siguiente agenda:

  • 18:00h – 18:15h Bienvenida. Receopción y bienvenida de asistentes.
  • 18:15h – 18:30h Novedades en Visual Studio para desarrollo UWP.  ¿Desarrollas aplicaciones universales Windows?. En esta sesión veremos algunas de las últimas novedades introducidas en Visual Studio destinadas para el desarrollo de UWP. Novedades como Editar y Continuar en XAML, novedades en depuración, etc.
  • 18:30h – 19:00h Desktop App Converter: De Win32 a UWP!. Llegar a la Windows Store es ahora más asequible que nunca. Si has invertido tiempo, esfuerzo y conocimientos en el desarrollo de aplicaciones Win32, ahora utilizando Project Centennial  te explicamos como convertirla en UWP y aprovechar todas las nuevas posibilidades disponibles, nuevas APIs, la Windows Store, nuevas formas de monetización y mucho más.
  • 19:00h – 20:00h Creando aplicaciones UWP para Xbox One. Llego el momento, por fin, podemos crear aplicaciones universales windows para Xbox One. En esta sesión veremos desde como activar cualquier Xbox One para el modo desarrollador hasta como adaptar nuestras aplicaciones para ofrecer la mejor experiencia.
  • 20:00h – 21:00h Introducción al desarrollo para HoloLens. Con las herramientas, emulador y todo lo encesario, nada mejor que ver las posibilidades de desarrollo con HoloLens, ¿cierto?.

La fecha

El evento tendrá lugar el próximo Jueves, 21 de Abril de 18:00h a 21:00h. Tendremos cuatro sesiones técnicas abordando algunas de las principales novedades en el desarrollo en la plataforma Windows.

El lugar

El evento se celebrará en la ETS de Ingeniería Informática. Dirección detallada:

E.T.S. Ingeniería Informática – Universidad de Sevilla
Av. Reina Mercedes s/n
Sevilla Se 41012

ETS de Ingeniería Informática

ETS de Ingeniería Informática

Si a pesar de todo el contenido de la agenda te parece poco, contaremos también con alguna sorpresa y regalo a sortear entre los asistentes.

¿Te apuntas?

Más información

[Windows 10] Imprimiendo desde nuestras Apps UWP

Print - 01Introducción

Con Windows 10 tenemos gran cantidad de novedades interesantes relacionadas con el desarrollo de aplicaciones empresariales. Desde el gran potencial de Continuum a novedades en la Store pasando por nuevas APIs para trabajar con datos biométricos, bluetooth, criptografía, etc. Entre todas las características que podríamos necesitar, brilla con luz propia la posibilidad de imprimir.

En este artículo vamos a centrarnos en las posibilidades disponibles en los namespaces Windows.Graphics.Printing y Windows.UI.Xaml.Printing.

Nuestra aplicación

Nuestro objetivo será crear una aplicación UWP que mostrará un listado de la compra permitiendo imprimir la misma.

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.

Comenzamos definiendo la vista de nuestro ejemplo:

<Grid>
     <Grid.RowDefinitions>
         <RowDefinition Height="*" />
         <RowDefinition Height="50" />
     </Grid.RowDefinitions>
     <StackPanel 
        x:Name="PrintableContent">
        <TextBlock 
             Text="Shopping List"
             FontWeight="Black"
             Margin="12"/>
         <ListView
             ItemsSource="{Binding Products}"/>
     </StackPanel>
     <Button 
        Grid.Row="1"
        Content="Print"
        HorizontalAlignment="Center"/>
</Grid>

Sencilla. Cuenta con un listado que mostrará el listado de productos a comprar además de un botón que tendrá como objetivo realizar la impresión de la lista. La lista se encuentra enlazada a una propiedad pública llamada Products:

private ObservableCollection<string> _products;
public ObservableCollection<string> Products
{
     get { return _products; }
     set
     {
          _products = value;
          RaisePropertyChanged();
     }
}

Una colección de cadenas que contendrá cada producto. Cargaremos una lista desde local para simplificar el ejemplo y centrar toda nuestra atención en la impresión.

private void LoadProducts()
{
     Products = new ObservableCollection<string>
     {
          "Milk",
          "Apples",
          "Water",
          "Chicken meat",
          "Coffee",
          "Yogurt",
     };
}

Si ejecutamos el ejemplo veremos:

Nuestro ejemplo

Nuestro ejemplo

Registro para imprimir

En nuestro ejemplo, donde utilizamos el patrón MVVM y otras buenas prácticas, vamos a crear un servicio de impresión lo más genérico posible con el objetivo de poder reutilizarlo de forma rápida y sencilla entre diferentes desarrollos.

El primer paso para poder imprimir desde nuestras aplicaciones pasa por el registro del contrato de impresión. Nuestra aplicación debe realizar este proceso en cada pantalla desde la que deseamos permitir imprimir. Sólo podremos registrar la vista activa por lo también debemos preocuparnos de un proceso en el que eliminar el registro. Si nuestra aplicación navega a una nueva vista de la que deseamos imprimir de una anterior registrada para la impresión, al salir de la previa debe eliminar el registro correctamente.

Para realizar las operaciones básicas de impresión entre las que se encuentra el registro debemos utilizar la clase PrintManager  disponible en el namespace Windows.Graphics.Printing. PrintManager lo utilizaremos para indicar que la aplicación desea participar en la impresión además de poder iniciar la misma programáticamente.

También utilizaremos la clase PrintDocument disponible en el namespace Windows.UI.Xaml.Printing. En esta clase contamos con los métodos y propiedades necesarias para establecer el contenido a enviar a la impresora.

Definimos dos variables con cada una de las clases anteriores en nuestro servicio:

protected PrintManager Printmgr;
protected PrintDocument PrintDoc;

Nos centrámos en el proceso de registro:

public virtual void RegisterForPrinting()
{
     PrintDoc = new PrintDocument();
     PrintDoc.Paginate += CreatePrintPreviewPages;
     PrintDoc.GetPreviewPage += GetPrintPreviewPage;
     PrintDoc.AddPages += AddPrintPages;

     Printmgr = PrintManager.GetForCurrentView();

     Printmgr.PrintTaskRequested += PrintTaskRequested;
}

Instanciamos las clases PrintManager y PrintDocument además de realizar la subscripción a los eventos necesarios.

Para realizar el registro del contrato de impresión desde nuestra ViewModel utilizando el servicio, lo inyectaremos vía constructor:

private IPrintService _printService;

public MainViewModel(IPrintService printService)
{
     _printService = printService;
}

Y utilizamos el método creado RegisterForPrinting:

_printService.RegisterForPrinting();

NOTA: Al salir de la vista debemos quitar la subscripción al contrato de impresión, es decir, todos los eventos a los que nos registramos durante el registro. Si contámos con una aplicación con múltiples vistas, sin elimimar la subscripción, si dejamos la vista y regresamos obtendremos una excepción.

El contenido a imprimir

Ya que tenemos lo suficiente para registrar el contrato de impresión, debemos establecer el contenido que deseamos imprimir. En nuestro ejemplo contámos con un listado de productos correspondientes a una lista de la compra que deseamos imprimir.

¿Cómo funciona?

protected UIElement PrintContent;

La clase UIElement es una clase base de la mayoría de elementos visuales en Windows Runtime. Podemos utilizar cualquier elemento visual derivado de esta clase para imprimir. Nuestro contenido de impresión será por lo tanto un UIElement.

Tenemos donde almacenar el contenido a imprimir, necesitaremos también la operación de impresión. Para ello, utilizaremos una instancia de la clase PrintTask, la operación de impresión, incluyendo el contenido.

protected PrintTask Task;

Cuando realizamos el registro del contrato de impresión, nos registramos a múltiples eventos entre los que destaca PrintTaskRequested. Este evento correspondiente al PrintManager será el primero en lanzarse cuando el usuario quiera imprimir y le mostremos la ventana con la previsualización del contenido.

protected virtual void PrintTaskRequested(PrintManager sender,
            PrintTaskRequestedEventArgs e)
{
     Task = e.Request.CreatePrintTask(PrintTitle, async sourceRequested =>
     {
          PrintTaskOptionDetails printDetailedOptions = PrintTaskOptionDetails.GetFromPrintTaskOptions(Task.Options);

          printDetailedOptions.DisplayedOptions.Clear();
          printDetailedOptions.DisplayedOptions.Add(StandardPrintTaskOptions.Copies);

          Task.Options.Orientation = PrintOrientation.Portrait;

          Task.Completed += async (s, args) =>
          {
               if (args.Completion == PrintTaskCompletion.Failed)
               {
                    await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                    {
                         Debug.WriteLine("Failed to print.");
                    });
               }
           };

           await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
           {
                sourceRequested.SetSource(PrintDoc?.DocumentSource);
           });
     });
}

En este evento, instanciamos PrintTask utilizando el método PrintTaskRequest.CreatePrintTask.

NOTA: Le podemos pasar una cadena de texto al método CreatePrintTask. Se mostrará el texto en el título de la ventana de previsualización del contenido a imprimir.

Tras crear la tarea de impresión, se verifica el número de páginas a imprimir. Se lanza el evento Paginate correspondiente a la interfaz IPrintPreviewPageCollection.

protected virtual void CreatePrintPreviewPages(object sender, PaginateEventArgs e)
{
     PrintDoc.SetPreviewPageCount(1, PreviewPageCountType.Final);
}

Este evento puede lanzarse en múltiples ocasiones. Cada vez que el usuario modifique parámetros de configuración en la vista de previsualización de la impresión, el evento se lanzará para ajustar el contenido.

NOTA: Hemos simplificado nuestro ejemplo añadiendo directamente una única página. Podemos definir y crear tantas páginas como sea necesario.

Cuando en la vista de previsualización se va a mostrar una página, se lanza el evento GetPreviewPage.

protected virtual void GetPrintPreviewPage(object sender, GetPreviewPageEventArgs e)
{
     PrintDocument printDoc = (PrintDocument)sender;
     printDoc.SetPreviewPage(e.PageNumber, PrintContent);
}

Sencillamente establecemos el contenido de previsualización al PrintDocument.

Por último, contámos con el evento AddPages del conjunto de eventos al que nos registramos al registrar el contrato de impresión.

protected virtual void AddPrintPages(object sender, AddPagesEventArgs e)
{
     PrintDoc.AddPage(PrintContent);

     PrintDoc.AddPagesComplete();
}

En este evento añadimos el contenido a añadir a la colección de páginas de PrintDocument, es decir, el contenido a enviar a la impresora.

Estableciendo el contenido

Tras repasar cada unos de los eventos que componen el proceso de impresión, ¿cómo añadimos contenido desde nuestra ViewModel?. En nuestro servicio:

public virtual void SetPrintContent(UIElement content)
{
     if (content == null)
          return;

     PrintContent = content;
}

Tenemos un sencillo método que nos permite establecer cualquier elemento de la interfaz derivado de UIElement como contenido.

Añadir contenido desde la ViewModel será muy sencillo:

_printService.SetPrintContent(GetPrintableContent());

Para añadir el contenido utilizamos un Helper que nos permite obtener un elemento específico de UI utilizando su nombre:

private UIElement GetPrintableContent()
{
     return VisualHelper.FindChild<UIElement>(
                Window.Current.Content, "PrintableContent");
}

El Helper hace uso internamente de la clase VisualTreeHelper.

Mostrar previsualización

Con el registro del contrato de impresión, preparación del contenido y todo lo necesario para poder imprimir, es hora de permitir la operación al usuario. En nuestr servicio, utilizaremos el método asíncrono ShowPrintUIAsync para mostrar una ventana modal al usuario con la previsualización del contenido, las opciones de impresión además de por supusto las opciones para completar o cancelar la impresión.

public async void ShowPrintUiAsync(string title)
{
     try
     {
          PrintTitle = title;

          await PrintManager.ShowPrintUIAsync();
     }
     catch (Exception e)
     {
          Debug.WriteLine("Error printing: " + e.Message + ", hr=" + e.HResult);
     }
}

Si en el momento de lanzar el método ShowPrintUIAsync la operación no es posible, se lanzará una excepción. Es importante capturar esta excepción y actuar en consecuencia, notificando al usuario.

Desde la ViewModel, utilizando nuestro servicio:

_printService.ShowPrintUiAsync("Print Sample");

La ventana de previsualización:

Previsualización de la impresión

Previsualización de la impresión

Además de la previsualización, podremos configurar las opciones de configuración. En estas opciones, además de configuraciones básicas como la impresora a elegir o el número de copias, podemos configurar orientación, modos de color y muchas otras opciones.

Tenéis el código fuente disponible en GitHub:

Ver GitHub

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

Más información

[Windows 10] Biometría de huellas dactilares

Finger PrintIntroducción

En muchos desarrollos móviles tenemos la necesidad de contar con seguridad para limitar su acceso. Cuando hablamos de seguridad lo primero que se nos viene a la mente es la autenticación. La autenticación habitual, es decir, con usuario y contraseña, requieren una serie de características como gestión de las credenciales, complejidad de la contraseña, recuperación, etc.

Con Windows 10 tenemos dos nuevas tecnologías destinidas a facilitar la gestión de la seguridad tanto para usuarios como para desarrolladores integrando la tecnologías en sus Apps. Estas tecnologías son:

  • Windows Hello
  • Microsoft Passport

Windows Hello

El primero de ellos es un framework biométrico que soporta:

  • Reconocimiento facial
  • Escaneo de Iris
  • Huella

NOTA: Windows Hello requiere de hardware específico como lector de huellas o sensor

Microsoft Passport

Microsoft Passport aporta un mecanismo de autenticación que reemplaza las clásicas contraseñas por una combinación del dispositivo  junto a un PIN definido por el usuario o bien datos biométricos aportados por Windows Hello.

Datos biométricos, uso de huellas dactilares

Nuestro objetivo en este artículo será revisar todas las posibilidades brindadas por UserConsentVerifier. Esta nueva clase introducida en Windows 10 nos permite comprobar la disponibilidad de dispositivo que permita realizar una verificación biométrica (huella dactilar).

En nuestro ejemplo, contaremos con una interfaz sencilla:

<StackPanel
     HorizontalAlignment="Center"
     VerticalAlignment="Center">
     <Button 
          Content="Check UserConsent Availability" 
          Command="{Binding AvailabilityCommand}" />
     <TextBlock 
          Text="Request UserConsent Verification"
          Margin="0,24,0,0"/>
     <TextBox 
          PlaceholderText="Insert Message..."
          Text="{Binding Message, Mode=TwoWay}"/>
     <Button 
          Content="Request UserConsent Verification" 
          Command="{Binding VerificationCommand}"
          IsEnabled="{Binding IsUserConsentAvalaible}"/>
</StackPanel>

Un primer botón que nos indique la disponibilidad de dispositivo que permita realizar una verificación biométrica mientras que el segundo nos permitirá realizar la verificación del usuario con los datos biométricos.

Ambos botones contarán con un comando asociado en la ViewModel. El primero:

private ICommand _availabilityCommand;       

public ICommand AvailabilityCommand
{
     get { return _availabilityCommand = _availabilityCommand ?? new DelegateCommandAsync(AvailabilityCommandExecute); }
}

public async Task AvailabilityCommandExecute()
{

}

Y el segundo:

private ICommand _verificationCommand;

public ICommand VerificationCommand
{
     get { return _verificationCommand = _verificationCommand ?? new DelegateCommandAsync(VerificationCommandExecute); }
}

public async Task VerificationCommandExecute()
{

}

Nada especial a destacar llegados aquí. Continuamos…

Detectar si contamos con lector de huellas

Para poder utilizar datos biométricos en nuestra aplicación debemos antes que nada verificar si el dispositivo cuenta con lector de huellas. Podemos utilizar el método UserConsentVerifier.CheckAvailabilityAsync para la verificación.

En el servicio:

public async Task<UserConsentVerifierAvailability> GetUserConsentAvailabilityAsync()
{
     UserConsentVerifierAvailability consentAvailability =
     await UserConsentVerifier.CheckAvailabilityAsync();
     
     return consentAvailability;
}

El resultado será un valor de la enumeración UserConsentVerifierAvailability. Los posibles valores de la enumeración son:

  • Available: Dispositivo de verificación biométrica disponible.
  • DeviceBusy: El dispositivo de verificación biométrica está realizando una operación y no está disponible.
  • DeviceNorPresent: No hay dispositivo de verificación biométrica.
  • DisabledByPolicy: Por directiva de grupo, la verificación biométrica esta deshabilitada.
  • NotConfiguredForUser: No hay dispositivo de verificación biométrica configurado por el usuario actual.

Desde la viewmodel de la aplicación utilizaremos el servicio para la verificación:

IsUserConsentAvalaible = await _userConsentVerifierService.CheckUserConsentAvailabilityAsync();

Hasta este punto tenemos lo necesario para detectar si contámos con la posibilidad de usar datos biométricos o no.

Solicitud de consentimiento

Llega el momento de usar datos biométricos. Tras verificar la disponibilidad del lector debemos pedir consentimiento utilizando el método UserConsentVerifier.RequestVerificationAsync.

En nuestro servicio:

public async Task<UserConsentVerificationResult> GetRequestUserConsentVerificationAsync(string message)
{
     UserConsentVerificationResult consentResult =
     await UserConsentVerifier.RequestVerificationAsync(message);

     return consentResult;
}

NOTA: Para que la autenticación con la huella funcione correctamente, el usuario debe habe registrado su huella previamente.

Desde la viewmodel, bastará con usar el método anterior:

var result = await _userConsentVerifierService.GetRequestUserConsentVerificationAsync(Message);

Como parámetro pasamos una cadena. Esta cadena se utilizará para mostrar un mensaje al usuario en la solicitud de comprobación biométrica. En cuanto al resultado, obtenemos un valor de la enumeración UserConsentVerificationResult:

switch(result)
{
     case Windows.Security.Credentials.UI.UserConsentVerificationResult.Canceled:
          message = "Consent request prompt was canceled.";
          break;
     case Windows.Security.Credentials.UI.UserConsentVerificationResult.DeviceBusy:
          message = "Biometric device is busy.";
          break;
     case Windows.Security.Credentials.UI.UserConsentVerificationResult.DeviceNotPresent:
          message = "Biometric device not found.";
          break;
     case Windows.Security.Credentials.UI.UserConsentVerificationResult.DisabledByPolicy:
          message = "Disabled by policy.";
          break;
     case Windows.Security.Credentials.UI.UserConsentVerificationResult.NotConfiguredForUser:
          message = "No fingeprints registered.";
          break;
     case Windows.Security.Credentials.UI.UserConsentVerificationResult.RetriesExhausted:
          message = "Too many retries.";
          break;
     case Windows.Security.Credentials.UI.UserConsentVerificationResult.Verified:
          message = "User verified.";
          break;
}

Los valores de la enumeración son:

  • Verified: Huella comprobada correctamente.
  • DeviceNotPresent: Dispositivo biométrico no disponible.
  • NotConfiguredForUser: No hay ningún dispositivo biométrico configurado por el usuario actualo.
  • DisableByPolicy: La directiva de grupo ha deshabilitado el dispositivo biométrico.
  • DeviceBusy: Dispositivo biométrico ocupado al encontrarse realizando una operación.
  • RetriesExhausted: Tras 10 intentos, la solicitud de comprobación original y todos los intentos han fallado.
  • Canceled: Cancelación de la operación.

Sencillo, ¿cierto?.

Si ejecutamos la aplicación en un Lumia con opción biométrica, como por ejemplo un Lumia 950XL, ofrecerá dos opciones de auenticación:

  • Escáner de Iris
  • Código PIN

Igual resultado obtendremos en un PC que cuente con RealSense. Sin embargo, si probamos en un dispositivo sin posibilidad de detección biométrica aun así nos permitirá la validación vía código PIN.

PIN Code

PIN Code

De forma evidente no es un mecanismo de autenticación biométrica pero si suficiente para cubrir las necesidades de la API.

Tenéis el código fuente disponible en GitHub:

Ver GitHub

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

Más información

[Tips and Tricks] Windows 10. Adaptar recursos por DPI de pantalla

Scale to Fit-02Introducción

Con Windows 10 los desarrolladores recibimos la culminación de un gran viaje en la convergencia entre las diferentes plataformas Windows. Ahora podemos desarrollar aplicaciones para gran diversidad de familias de dispositivos como móviles, PCs, tabletas, IoT y otros que están por llegar, compartiendo la mayor cantidad de código, con un mismo proyecto y paquete. Además, contamos con grandes nuevas características como Continuum en teléfonos que permite convertirlo en un PC utilizando Microsoft Display Dock o Miracast.

Sin embargo, hay un detalle claro y obvio. Si contamos con un mismo paquete para todos esos dispositivos diferentes…¿cómo adaptamos la experiencia para ofrecer la mejor opción adaptada posible?

Debemos adaptar la interfaz de usuario en cada familia de plataforma para lograr ofrecer la mejor experiencia posible adaptada a la perfección. Para ello, utilizamos:

  • AdaptiveTriggers
  • Nuevos controles como RelativePanel y/o SplitView
  • Detección de modos de interacción
  • Etc

Sin embargo, hay elementos vitales en la mayoría de aplicaciones, que no acaban recibiendo la atención que se merecen. Estoy hablando de las imagenes. La aplicación puede usar una imagen que se visualiza perfectamente en un teléfono pero…¿y si se usa la aplicación con Continuum en una pantalla con una resolución diferente (más elevada)?.

En este artículo, vamos a aprender como organizar y utilizar los recursos de la aplicación para que se utilicen y adapten por DPI.

DisplayInformation

La clase DisplayInformation cuenta con propiedades y eventos que nos permiten verificar y monitorear información relacionada con la pantalla física. Para monitorear detalles como cambios en DPI o la rotación podemos usar la clase DisplayInformation.

En nuestra interfaz vamos a mostrar la siguiente información:

<StackPanel
     Orientation="Horizontal">
     <TextBlock Text="Logical DPI:" />
     <TextBlock Text="{Binding LogicalDpi}" />
     <TextBlock Text="DPI" />
</StackPanel>

<StackPanel
     Orientation="Horizontal">
     <TextBlock Text="Scaling:" />
     <TextBlock Text="{Binding Scale}" />
     <TextBlock Text="%" />
</StackPanel>

De modo que, en la viewmodel bindeada definiremos dos propiedades:

private string _logicalDpi;
public string LogicalDpi
{
     get { return _logicalDpi; }
     set
     {
          _logicalDpi = value;
          RaisePropertyChanged();
     }
}

private string _scale;
public string Scale
{
     get { return _scale; }
     set
     {
          _scale = value;
          RaisePropertyChanged();
     }
}

Una para cada valor que deseamos mostrar en pantalla. Utilizaremos el método DpiChanged lanzado cada vez que la propiedad LogicalDpi se modifica, cuando cambian los píxeles por pulgada (PPI) de la pantalla.

private DisplayInformation _displayInformation;

_displayInformation = DisplayInformation.GetForCurrentView();

Tras obtener la información física actual de la pantalla utilizando el método GetForCurrentView nos suscribimos al evento DpiChanged:

_displayInformation.DpiChanged += _displayInformation_DpiChanged;

Cada vez que el evento se lanza, actualizamos la información mostrada en pantalla:

private void _displayInformation_DpiChanged(DisplayInformation sender, object args)
{
     DisplayInformation displayInformation = sender as DisplayInformation;

     UpdateDpi(displayInformation);
}

private void UpdateDpi(DisplayInformation displayInformation)
{
     if (displayInformation != null)
     {
          LogicalDpi = displayInformation.LogicalDpi.ToString();
          Scale = (displayInformation.RawPixelsPerViewPixel * 100.0).ToString();
     }
}

Mostramos los píxeles por pulgada lógica de la pantalla actual utilizando la propiedad LogicalDpi, mientras que para la escala utilizamos la propiedad RawPixelsPerViewPixel que indica el número de píxeles físicos (RAW) por cada  pixel mostrado (Layout). Para obtener la escala bastará con multiplicar el valor por cien.

NOTA: En este ejemplo utilizamos la clase DisplayInformation para mostrar información contextual relacionada con el escalado de imágenes utilizado. Sin embargo, utilizando propiedades como DiagonalSizeInInches podemos saber facilmente el tamaño en pulgadas de la pantalla y así adaptar la interfaz en consecuencia. Sumamente útil y sencillo combinado con el uso de AdaptiveTriggers personalizados.

Recursos por DPI

Para optimizar nuestra interfaz en cada posible dispositivo o condición, podemos facilitar diferentes assets para diferentes resoluciones y escalas. Cada dispositivo cuenta con una escala específica resultante de la densidad de píxeles física y la distancia de visión teórica.

La escala es utilizada por el sistema, que realiza una gestión de recursos para determinar que recurso es el más adecuado entre las opciones facilitadas por los desarrolladores en sus aplicaciones.

NOTA: Los teléfonos suelen tener una escala de entre 200 y 400 mientras que dispositivos conectados como monitores y TVs tiene valores de 100 y 150 respectivamente.

Ejemplos de escala

Ejemplos de escala

Añadiendo recursos por escala

Para soportar el uso de diferentes recursos dependientes de la escala, bastará con añadirlos de la forma adecuada. Contamos con dos formas diferentes para ello.

Por un lado, podemos sencillamente añadir el mismo recurso con diferentes tamaños utilizando la notación .scale-xxx dentro de la carpeta Assets:

Recursos por DPI

Recursos por DPI

Por otro lado, podemos añadir diferentes carpetas con el nombre de la escala, es decir, scale-xxx incluyendo como contenido los recursos.

Utilizando recursos por escala

En nuestra carpeta de Assets contamos con una imágen única llamada Picture-NoScale:

<Image
     Source="ms-appx:///Assets/Picture-NoScale.png"
     Height="100"
     Width="100"
     HorizontalAlignment="Left"/>

Con el código anterior, usaremos la misma (y única) imágen existente bajo cualquier condición. Si la escala es alta y requiere de recursos con mayor resolución, el resultado será una visualización borrosa de la misma. Proporcionamos una experiencia no idónea.

Contamos con múltiples opciones por escala del  recurso llamado Picture, bastará con utilizarlo ignorando scale-xxx de la ruta:

<Image
    Source="ms-appx:///Assets/Picture.png"
    Height="100"
    Width="100"
    HorizontalAlignment="Left"/>

Utilizando los recursos vistos previamente, donde en un caso usamos una imágen única bajo cualquier condición y en otro una adapada a diferentes escalas, el resultado es el siguiente:

Carga de Assets por DPI

Carga de Assets por DPI

Tenemos 192DPI con una escala de 200%. Podemos ver a simple vista que mientras que la primera imágen se visualiza pixelada, la segunda se aprecia con una calidad alta.

Sencillo, ¿cierto?

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

[Windows 10] Experiencias multipantalla utilizando ProjectionManager

Introducción

Entre el conjunto de posibilidades nuevas disponibles con Windows 10, sin duda alguna, hay una brilla fuertemente sobre las demas, Continuum. Esta característica permite conectar un teléfono a un monitor externo permitiendo interactuar con la App en modo escritorio mientras podemos continuar utilizando el teléfono.

Continuum

Continuum

Es vital utilizar los nuevos AdaptiveTriggers, RelativePanel además de controlar el modo de interacción y otros detalles para adaptar la interfaz y usabilidad a cada posible situación. De esta forma conseguimos aplicaciones adaptativas pudiendo ofrecer la experiencia idónea en cada familia de dispositivo soportado.

En Continuum podemos tener una única App en la pantalla secundaria de forma simultánea. Sin embargo, podemos crear experiencias con múltiples pantallas. ¿Os imagináis ver listado de restaurantes cercanos en el teléfono mientras que en pantalla grande vemos mapa mostrando cercanía a nuestra posisión y críticas?, ¿ tener detalles de una película y ver el trailer de la misma en pantalla completa?. Escenarios donde sacar partido de la proyección de información a una pantalla secundaria hay muchos tanto en aplicaciones como en juegos. En este artículo vamos a sacarle todo el partido a la clase ProjectionManager y el trabajo multipantalla.

ProjectionManager

ProjectionManager

Proyección de vistas

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.

El objetivo del artículo será proyectar una pantalla secundaria para aprender a:

  • Proyectar pantalla secundaria.
  • Detener la proyección.
  • Hacer un intercambio de la pantalla donde se proyecta.

Detectar pantalla secundaria

ProjectionManager nos permite proyectar una ventana de nuestra App en una pantalla secundaria. A nivel de desarrollo, el proceso es similar a trabajar con múltiples ventanas en la misma App. Para proyectar en otra pantalla lo primero que debemos verificar es si disponemos de esa pantalla.

En nuestro ejemplo, mostraremos en la interfaz si contamos o no con la pantalla donde proyectar:

<TextBlock 
     Text="{Binding IsProjectionDisplayAvailable}"/>

Usaremos una sencilla propiedad bool en la viewmodel:

private bool _isProjectionDisplayAvailable;

public bool IsProjectionDisplayAvailable
{
     get { return _isProjectionDisplayAvailable; }
     set
     {
          _isProjectionDisplayAvailable = value;
          RaisePropertyChanged();
     }
}

En la clase ProjectionManager contamos con el evento ProjectionDisplayAvailableChanged que se lanza cada vez que la pantalla secundaria sobre la que proyecta pasa a estar disponible o no disponible:

ProjectionManager.ProjectionDisplayAvailableChanged += ProjectionManager_ProjectionDisplayAvailableChanged;

También podemos realizar la verificación de si tenemos disponible la pantalla secundaris utilizando la propiedad ProjectionDisplayAvailable:

IsProjectionDisplayAvailable = ProjectionManager.ProjectionDisplayAvailable;

NOTA: Si no contamos con pantalla secundaria, la vista proyectada se mostrará en la misma pantalla donde se encuentra la vista principal.

Proyectar

Conocemos como verificar si contamos con pantalla secundaria sobre la que proyectar, veamos como realizar la proyección.

En nuestra interfaz tendremos un botón que nos permitirá proyectar una vista específica:

<Button 
     Content="Project"
     Command="{Binding ProjectCommand}"/>

Nuestra interfaz principal:

Vista principal

Vista principal

El comando a ejecutar:

private ICommand _projectCommand;

public ICommand ProjectCommand
{
     get { return _projectCommand = _projectCommand ?? new DelegateCommandAsync(ProjectCommandExecute); }
}

public async Task ProjectCommandExecute()
{
     App.MainViewId = await _projectionService.ProjectAsync(typeof(ProjectionView));
}

Hemos creado un servicio ProjectionService en el que tenemos agrupada toda la lógica de proyección. Para proyectar utilizamos el siguiente método:

public async Task<int> ProjectAsync(Type viewType, DeviceInformation device = null)
{
     int mainViewId = ApplicationView.GetForCurrentView().Id;
     int? secondViewId = null;

     var view = CoreApplication.CreateNewView();
     await view.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
     {
          secondViewId = ApplicationView.GetForCurrentView().Id;
          var rootFrame = new Frame();
          rootFrame.Navigate(viewType, null);
          Window.Current.Content = rootFrame;
          Window.Current.Activate();
     });

     if (secondViewId.HasValue)
     {
          if(device == null)
              await ProjectionManager.StartProjectingAsync(secondViewId.Value, mainViewId);
          else
              await ProjectionManager.StartProjectingAsync(secondViewId.Value, mainViewId, device);
     }

     return mainViewId;
}

Para realizar la proyección utilizamos el método StartProjectingAsync(Int32,Int32) al que le pasamos como parámetros:

  • ProjectionViewId: El  identificador de la ventana que se va a mostrar en la pantalla secundaria.
  • AnchorViewId: El identificador de la ventana original.

Comenzamos creando una nueva vista vacía en blanca. En esta vista navegamos a la vista que deseamos proyectar y la asignamos como contenido. Podemos pasar los parámetros necesarios en este punto.

NOTA: Es totalmente necesario realizar la llamada a Window.Current.Activate para que la vista pueda visualizarse.

La vista no aparecerá hasta lanzar el método StartProjectingAsync. Tras lanzarlo, colocamos una vista existente en una pantalla secundaria, en caso de detectar una. De lo contrario, la vista se sitúa en el monitor principal.

Proyectar seleccionando la pantalla

Lo visto hasta este punto es sencillo y efectivo. Sin embargo, podemos tener situaciones más complejas con múltiples pantallas sencundarias.

¿Podemos elegir sobre que pantalla proyectar?

Si, podemos. Vamos a ver como realizar este proceso. Creamos en la interfaz otro botón de modo que al ser pulsado nos muestre todas las pantallas disponibles. Una vez seleccionada una pantalla específica proyectaríamos sobre la misma:

<Button 
     Content="Select Target and Project"
     Command="{Binding SelectTargetCommand}"/>
<ListView 
     ItemsSource="{Binding Devices}"
     SelectedItem="{Binding SelectedDevice, Mode=TwoWay}"
     Height="300"
     Width="300"
     HorizontalAlignment="Left">
     <ListView.ItemTemplate>
          <DataTemplate>
               <TextBlock Text="{Binding Name}" />
          </DataTemplate>
     </ListView.ItemTemplate>
</ListView>

En la viewmodel:

private ICommand _selectTargetCommand;

public ICommand SelectTargetCommand
{
     get { return _selectTargetCommand = _selectTargetCommand ?? new DelegateCommandAsync(SelectTargetCommandExecute); }
}

public async Task SelectTargetCommandExecute()
{
     try
     {
          Devices = new ObservableCollection<DeviceInformation>(await _projectionService.GetProjectionDevices());
     }
     catch (Exception ex)
     {
          Debug.WriteLine(ex.Message);
     }
}

Utilizamos el siguiente método:

public async Task<IEnumerable<DeviceInformation>> GetProjectionDevices()
{
     // List wired/wireless displays
     String projectorSelectorQuery = ProjectionManager.GetDeviceSelector();

     // Use device API to find devices based on the query 
     var projectionDevices = await DeviceInformation.FindAllAsync(projectorSelectorQuery);

     var devices = new ObservableCollection<DeviceInformation>();
     foreach (var device in projectionDevices)
          devices.Add(device);

     return devices;
}

Utilizamos el método GetDeviceSelector disponible en ProjectionManager que nos devuelve una cadena con la enumeración de dispositivos disponibles. Utilizamos la cadena para obtener una colección de dispositivos (DeviceInformation) en los cuales tenemos toda la información necesaria.

La colección obtenida es la que bindeamos a nuestra interfaz. Una vez seleccionado un dispositivo concreto:

private async Task Project(DeviceInformation device)
{
     try
     {
          // Show the view on a second display (if available) 
          App.MainViewId = await _projectionService.ProjectAsync(typeof(ProjectionView), device);

          Debug.WriteLine("Projection started in {0} successfully!", device.Name);
     }
     catch (Exception ex)
     {
          Debug.WriteLine(ex.Message);
     }
}

Utilizamos un método al que le pasamos el dispositivo y se encarga de realizar la proyección. En este caso, en nuestro servicio utilizamos el método StartProjectingAsync(Int32,Int32,DeviceInformation) donde además de los identificadores de la nueva vista y de la original, indicamos el dispositivo, es decir, la pantalla específica sobre la que proyectar.

También podemos de forma muy sencilla permitir elegir el dispositivo sobre el que proyectar utilizando el método RequestStartProjectingAsync(Int32,Int32,Rect,Placement). Utilizando este método se mostrará un flyout con el listado de dispositivos, de modo que, una vez seleccionado uno, comenzamos la proyección. Para indicar la posición del flyout podemos utilizar un parámetro de tipo Rect.

public async Task<int> RequestProjectAsync(Type viewType, Rect? position = null)
{
     int mainViewId = ApplicationView.GetForCurrentView().Id;
     int? secondViewId = null;

     var view = CoreApplication.CreateNewView();
     await view.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
     {
          secondViewId = ApplicationView.GetForCurrentView().Id;
          var rootFrame = new Frame();
          rootFrame.Navigate(viewType, mainViewId);
          Window.Current.Content = rootFrame;
          Window.Current.Activate();
     });

     if (secondViewId.HasValue)
     {
          var defaultPosition = new Rect(0.0, 0.0, 200.0, 200.0);
          await ProjectionManager.RequestStartProjectingAsync(secondViewId.Value, mainViewId, position.HasValue ? position.Value : defaultPosition);
     }

     return mainViewId;
}

La vista proyectada

¿Y que ocurre con la vista proyecta?. Nada en especial, puede ser cualquier vista de la aplicación. Sin embargo, puede llegar a interesarnos realizar algunas interacciones con la API de proyección como:

  • Detener la proyección.
  • Modificar el dispositivo donde proyectamos.

La interfaz de usuario contará con dos botones, uno para detener la proyección y otro para modificar el dispositivo utilizado.

<Grid>
     <StackPanel>
          <TextBlock
              Text="Projection View"
              FontWeight="SemiBold"/>
          <Button 
              Content="Swap"
              Command="{Binding SwitchViewCommand}"/>
          <Button
              Content="Stop"
              Command="{Binding StopCommand}"/>
     </StackPanel>
</Grid>

El resultado:

Vista proyectada

Vista proyectada

En la viewmodel:

private ICommand _switchViewCommand;
private ICommand _stopCommand;

public ICommand SwitchViewCommand
{
     get { return _switchViewCommand = _switchViewCommand ?? new DelegateCommandAsync(SwitchViewCommandExecute); }
}

public ICommand StopCommand
{
     get { return _stopCommand = _stopCommand ?? new DelegateCommandAsync(StopCommandExecute); }
}

public async Task SwitchViewCommandExecute()
{
     try
     {
          await _projectionService.SwitchProjection(App.MainViewId);
     }
     catch (Exception ex)
     {
          Debug.WriteLine(ex.Message);
     }
}

public async Task StopCommandExecute()
{
     try
     {
          await _projectionService.StopProjection(App.MainViewId);
     }
     catch (Exception ex)
     {
          Debug.WriteLine(ex.Message);
     }
}

Detener proyección

Para detener la proyección tenemos a nuestra disposición el método StopProjectingAsync que oculta la vista mostrada en proyector o pantalla secundaria.

public async Task StopProjection(int mainViewId)
{
     await ProjectionManager.StopProjectingAsync(       
                ApplicationView.GetForCurrentView().Id,
                mainViewId);
}

Cambiar pantalla

Podemos cambiar al vuelo la pantalla donde se realiza la proyección utilizando el método SwapDisplaysForViewsAsync de la clase ProjectionManager:

public async Task SwapProjection(int mainViewId)
{
     await ProjectionManager.SwapDisplaysForViewsAsync(
                ApplicationView.GetForCurrentView().Id,
                mainViewId);
}

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] Talks4Kids 2015: Consejos Heisenberg para conseguir Apps Windows 10 con 99% de pureza

ChildrenEl evento

Todos los eventos de comunidad son especiales ya por el sencillo hecho de compartir, comunicar y hacer networking entre todos. Sin embargo, en ocasiones hay eventos que marcan. Lo pueden hacer por muchas razones, un evento grande de comunidad donde compartir y aprender mucho, el primer evento de una nueva comunidad, uno donde por temática o novedad te encuentras especialmente ilusionado. Hay muchos motivos.

El pasado 4 de Diciembre, en Microsoft Ibérica, tenía lugar el Talks4Kids. Evento de comunidad con sesiones técnicas relacionadas con tecnologías Microsoft pero diferente por varios motivos.

Por un lado, el evento era solidario buscando ayudar en la cantidad de lo posible a la fundación Theodora en su gran labor alegrando la estancia en hospitales tanto a pacientes como a sus familiares sobretodo en estas fechas señaladas. Nos complace de lleno saber que gracias a patrocinadores, ponentes y asistentes conseguimos aproximadamente unas 190 visitas de los doctores sonrisa.

Por otro lado, lanzamos un reto sencillo y directo. Si llegábamos a una cifra mínima de recaudación, todos los ponentes saldríamos disfrazados. Y vaya si lo hicimos…

Momento "Di mi nombre"

Momento “Di mi nombre”

Entre el distentido climax logrado gracias a la visita de un doctor sonrisa en la keynote, los momentos claves de aparición de cada ponente disfrazado, los irremediables momentos llenos de risas, la cercanía en las sesiones y el compañerismo absoluto, logramos uno de los eventos de comunidad más destacables del año.

Gran evento, gran comunidad!

Gran evento, gran comunidad!

Tenéis a continuación una pequeña galería con algunos de los momentos clave del evento.

El material

En cuanto al material del evento, participé con una sesión sobre desarrollo Windows 10 donde asociando en todo momento con el ya mítico personaje de la serie de ficción “Breaking Bad” vimos:

  • El ciclo de vida en aplicaciones Windows 10.
  • Ejecución de modo extendido.
  • Tareas de fondo, nuevos triggers.
  • Application Trigger.
  • Comunicación entre Apps.
  • App Services.

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

En cuanto a las demos técnicas realizadas, las tenéis disponible en GitHub:

Ver GitHub

Quisiera terminar añadiendo algunos agradecimientos a todos aquellos que han hecho posible el evento y toda la ayuda lograda. Comienzo agradeciendo a todos los patrocinadores que apoyaron al evento, en especial en mi caso particular, a Plain Concepts por no dudar ni un segundo en colaborar además de permitirme participar; gracias a todos los ponentes (y grandes amigos) por su compromiso, sesiones y por no dudar en disfrazarse o realizar lo necesario; a Microsoft por dejarnos sala y toda la ayuda necesaria y por supuesto, muchas gracias a todos los asistentes y los que no pudieron pero ayudaron.

Patrocinadores

Patrocinadores

One mor thing…

Todas las sesiones del evento fueron grabadasy estarán disponibles en Channel 9. Ante todo esto solo me queda decir, el año próximo… ¿repetimos?

Más información

[Tips and Tricks] DeviceFamily Adaptive XAML Tool

WindowsIntroducción

Con la llegada del SDK de Windows 10 Preview tenemos la posibilidad de crear Apps Universales con un único binario que funcione en múltiples plataformas. Es un paso importante pero que conlleva realizar una acción que sera comun, diferenciar entre las diferentes plataformas donde correrá dicho binario para poder adaptar la interfaz de usuario. Con ese objetivo utilizamos entre otras opciones los Adaptive Triggers de los que ya hemos hablado.

Sin embargo, en ocasiones la misma vista en diferentes dispositivos puede que sea totalmente diferente.

En estos casos podemos crear vistas diferentes por familias de dispositivos. Tras añadir una vista de la forma habitual, creamos una carpeta siguiente la siguiente nomenclatura:

  • DeviceFamily-[Family]

Donde Family es la familia del dispotivo para el que deseamos sobrescribir la vista.Dentro de esta carpeta añadimos la vista XAML deseada en esa plataforma.

NOTA: Añadimos la sobreescritura de la vista. Es importante un detalle del fichero añadido, no añadimos code behind. Esta vista utilizará el mismo code behind que la que teníamos previamente.

DeviceFamily Adaptive XAML Tool

Gestionar carpetas o vistas por familia de dispositivo se vuelve aun más sencillo gracias a la extensión Device Family Adaptive XAML Tool creada por Olivier Matis.

Podemos hacer clic derecho sobre la solución para acceder a un menu contextual llamado “Add single folder” para añadir carpeta de vistas específica para una plataforma concreta. Además, haciendo clic sobre una vista existente tendremos acceso a otro menu contextual “Add device family XAML” que nos creará la vista XAML específica para la familia de dispositivos seleccionada.

DeviceFamily Adaptive XAML Tool

DeviceFamily Adaptive XAML Tool

Sencillo pero extremadamente útil, ¿cierto?.

Más información