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

Introducción

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

Navegación

Creamos un nuevo proyecto:

Nueva App UAP

Nueva App UAP

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

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

  • FirstView
  • SecondView

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

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

El resultado visual:

Vista principal

Vista principal

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

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

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

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

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

Nuestra segunda página sera similar a la primera:

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

Contará con su propia viewmodel:

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

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

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

Todas nuevas ViewModels derivan de la ViewModelBase:

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

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

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

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

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

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

El resultado:

Botón volver en la Title Bar

Botón volver en la Title Bar

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

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

Ver GitHub

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

Más información

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *