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

PreviousIntroducción

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

Navegación

Creamos un nuevo proyecto:

Nueva App UAP

Nueva App UAP

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

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

  • FirstView
  • SecondView

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

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

El resultado visual:

Vista principal

Vista principal

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

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

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

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

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

Nuestra segunda página sera similar a la primera:

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

Contará con su propia viewmodel:

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

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

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

Todas nuevas ViewModels derivan de la ViewModelBase:

public abstract class ViewModelBase : INotifyPropertyChanged
{
     public event PropertyChangedEventHandler PropertyChanged;

     public virtual Task OnNavigatedFrom(NavigationEventArgs args)
     {
         return null;
     }

     public virtual Task OnNavigatedTo(NavigationEventArgs args)
     {
         return null;
     }

     public void RaisePropertyChanged([CallerMemberName]string propertyName = "")
     {
         var Handler = PropertyChanged;
         if (Handler != null)
            Handler(this, new PropertyChangedEventArgs(propertyName));
     }
}

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

Frame rootFrame = Window.Current.Content as Frame;

if (rootFrame.CanGoBack)
     SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
else
     SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Collapsed;

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

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

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

El resultado:

Botón volver en la Title Bar

Botón volver en la Title Bar

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

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

Ver GitHub

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

Más información

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