[Evento CartujaDotNet] De 0 a tu startup… sorteando los problemas?

El evento

En los tiempos que corren, no es fácil abrirse camino en un mundo tecnológico complejo, lleno de adversidades y competencia. Hacerlo con éxito, es todo un reto.

Somos conscientes de ellos, por ese motivo, desde CartujaDotNet organizamos un evento más mesa redonda donde Josué Yeray, MVP de Windows y cofundador de DevsDna nos mostrará todas las claves del camino a recorrer, papeles y requisitos a cumplir, detalles a tener en cuenta, consejos, filosofía a utilizar y muchos otros aspectos para iniciar tu startup.

Tras un repaso, recorrido y consejos, contaremos con una divertida mesa redonda donde entre todos trataremos aspectos como las claves, filosofías que triunfan y qu evitar, dudas, preguntas y mucho más.

La agenda

La agenda específica del evento será:

  • 18:00h – 19:30h: De 0 a tu startup… sorteando los problemas?
  • 19:30h – 20:00h: Mesa redonda

La fecha

El evento tendrá lugar el próximo Jueves, 04 de Mayo de 18:00h a 20:00h. Tendremos tiempo para sesión, mesa redonda y mucho más!

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

¿Te apuntas?

Más información

[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 necesario, nada mejor que ver las posibilidades de desarrollo con HoloLens, ¿cierto?.

Una agenda completa repleta de grandes novedades de la mano de Josué Yeray y un servidor.

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

[Xamarin.Forms] Backgrounding y persistencia de datos

Save-01-WFIntroducción

En dispositivos móviles contamos con una aplicación en primer plano. Cuando cambiamos de aplicación, si el usuario vuelve a la anterior, normalmente las aplicaciones vuelven a la última pantalla en la que se encontraba el usuario, con los datos e información que el usuario dejo. Todo listo y preparado para continuar. Un detalle que parece trivial pero que hoy día es necesario y esperado en cualquier aplicación.

Como desarrolladores debemos conocer el ciclo de vida de las aplicaciones móviles, la gestión y persistencia de información y como aplicar todo ese conocimiento para otorgar la mejor experiencia posible al usuario en cada plataforma.

En este artículo, vamos a aprender como realizar la persistencia de información de la aplicación en el ciclo de vida de la misma en Xamarin.Forms.

Eventos ciclo de vida

En Xamarin.Forms contamos con la clase Application donde establecemos el punto de entrada de la aplicación además de contar con métodos virtuales que podemos sobreescribir para gestionar el ciclo de vida de la aplicación:

  • OnSleep: Este evento se lanza cuando la aplicación pasa a background.
  • OnResume: Lanzado cuando la aplicación se resume después de estar en background.
protected override void OnStart()
{
    Debug.WriteLine ("OnStart");
}
protected override void OnSleep()
{
    Debug.WriteLine ("OnSleep");
}
protected override void OnResume()
{
    Debug.WriteLine ("OnResume");
}

Properties Dictionary

Desde la llegada de Xamarin.Forms 1.3 tenemos a nuestra disposición Application.Current.Properties. Ideal para utilizar en la suspensión y reanudación de la aplicación. Estamos ante un Dictionary con un uso muy sencillo que se encarga automáticamente del almacenamiento de datos en local.

Guardar

Utilizando Application.Current.Properties bastará con crear una nueva clave y asignar el valor:

Application.Current.Properties ["value"] = 1;

Leer

Recuperamos el valor utilizando la clave:

if (Application.Current.Properties.ContainsKey("value"))
{
     var val = Convert.ToInt32(Application.Current.Properties["value"]);
}

NOTA: Importante resaltar que como con el trabajo de cualquier diccionario, debemos verificar previamente la existencia del valor dado la clave otorgada.

Eliminar

En caso de desear eliminar el valor, de nuevo utilizamos la clave:

if (Application.Current.Properties.ContainsKey("value"))
{
     Application.Current.Properties.Remove("value");
}

Detalles a tener en cuenta

Debemos tener en cuenta que:

  • El valor asignado a una clave solo se guardará cuando se realice la suspensión de la aplicación (método OnSleep()). Es importante tener este detalle en cuenta ya que ante un cierre inesperado o bien en depuración al parar la misma, no guardaremos el valor al no realizarse la suspensión.
  • Al trabajar con un diccionario podemos guardar practicamente cualquier cosa, incluso entidades de clases propias que se serializarán.
  • Con Xamarin.Forms 1.4 se añadió un método adicional llamado SavePropertiesAsync() que podemos utilizar para guardar programáticamente cualquier cambio.

Persistencia de datos en Apps Xamarin.Forms

Para probar la persistencia de información junto al ciclo de vida de la aplicación vamos a crear un ejemplo Xamarin.Forms sencillo donde tendremos un formulario básico y guardaremos y recuperaremos la información al suspender y reanudar la aplicación.

Creamos la interfaz básica a utilizar:

<Grid
    VerticalOptions="Start">
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="100" />
      <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Label Grid.Column="0" Grid.Row="0" Text="First Name" VerticalOptions="End" />
    <Entry Grid.Column="1" Grid.Row="0" Text="{Binding FirstName, Mode=TwoWay}" />
</Grid>

El resultado:

Nuestra UI
Nuestra UI

En la viewmodel la propiedad bindeada:

private string _firstName;

public string FirstName
{
     get { return _firstName; }
     set
     {
          _firstName = value;
          RaisePropertyChanged();
     }
}

En la clase Application contamos con los métodos para gestionar el ciclo de vida de la aplicación. Como hemos visto, contamos con el método OnSleep() lanzado cuando la aplicación pasa a segundo plano. En este punto accederemos a la propiedad FirstName bindeada a la UI de la viewmodel y la guardaremos utilizando Properties Dictionary:

Application.Current.Properties["FirstName"] = viewModel.FirstName;   

Cuando la aplicación se resume, se lanza el evento OnResume(). En este punto verificamos la existencia de la propiedad FirstName y en caso de existir, la asignamos en nuestra viewmodel:

if (Application.Current.Properties.ContainsKey("FirstName"))
{
     var firstName = (string)Application.Current.Properties["FirstName"];
  
     viewModel.FirstName = firstName;
}

Podéis acceder al código fuente directamente en GitHub:

Ver GitHub

Más información

[Material SVQXDG] Sevilla Xamarin Dev Day

RDXWoY7W_400x400El evento

El pasado 06 de Abril, desde el grupo SVQXDG, desarrolladores Xamarin de Sevilla, organizábamos el Sevilla Xamarin Dev Day. Un evento donde tener hueco a sesiones técnicas, analizar y aclarar cualquier duda relacionada con los últimos anuncios del //BUILD 2016 además de tener momento para el networking y algun que otro detalle con los asistentes.

El material

En mi caso, pude participar con una sesión casi obligatoria donde repasábamos los cambios fundamentales anunciados en el pasado //BUILD como:

  • Xamarin incluido sin coste adicional en todas las versiones de Visual Studio.
  • Xamarin Core o Xamarin.Forms Open Source.
  • La integración de Xamarin Insights a HockeyApp.
  • Otros aspectos como el progreso de Xamarin Test Cloud, Xamarin University, etc.

La presentación utilizada la tenéis disponible a continuación:

Posteriormente, continuamos con una sobre de desarrollo con Xamarin.Forms, donde vimos todas las claves para adaptar las aplicaciones a tabletas.

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 y Marcos Cobeña por participar junto a un servidor en las sesiones y por supuesto, muchas gracias a todos los asistentes.

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