[Windows 10] Trabajando con múltiples ventanas

WindowsIntroducció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

3 pensamientos en “[Windows 10] Trabajando con múltiples ventanas

  1. Comienzo por agradecerte el notable aporte que haces a la comunidad de desarrolladores, y aprovecho para consultarte (mejor dicho pedirte) si es posible publicar una serie de artículos cubriendo de principio a fin un ejemplo de aplicación UWP (Win-10) en C# para Línea de Negocio (básicamente formularios y grillas para grandes volúmenes de datos).
    No hay mucho material con este tipo de ejemplos, y mucho menos con la calidad de tus publicaciones.

    Ojala sea posible hacerlo.

    Gracias
    Marcelo.-

    • Hola Marcelo,

      Muchas gracias, me alegra que los artículos te sean de utilidad. Tenía en mente un par de artículos relacionados, validación de campos en un formulario y estilos para mensajes de error, etc. Me apunto la idea de hacerlo en modo App paso a paso.

      De nuevo, gracias por tu comentario.

      Un saludo.

  2. Pingback: [Windows 10] Experiencias multipantalla utilizando ProjectionManager | Javier Suárez | Blog

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s