Condividi tramite


Spostamento indietro per le app UWP

API importanti: classe Windows.UI.Xaml.Controls.Frame , classe Windows.UI.Xaml.Controls.Page , spazio dei nomi Windows.UI.Xaml.Navigation , OnNavigatedTo

Per implementare lo spostamento indietro nell'app, posizionare un pulsante Indietro nell'angolo superiore sinistro dell'interfaccia utente dell'app. L'utente si aspetta che il pulsante Indietro passi alla posizione precedente nella cronologia di navigazione dell'app. Per impostazione predefinita, il controllo Frame registra le azioni di spostamento in BackStack e ForwardStack. Tuttavia, è possibile modificare le azioni di navigazione aggiunte alla cronologia di navigazione.

Per la maggior parte delle app con più pagine, è consigliabile usare il controllo NavigationView per fornire il framework di spostamento per l'app. Si adatta a un'ampia gamma di dimensioni dello schermo e supporta sia gli stili di navigazione in alto che a sinistra. Se l'app utilizza il controllo NavigationView, puoi usare il pulsante Indietro incorporato di NavigationView.

Annotazioni

Le linee guida e gli esempi in questo articolo devono essere usati quando si implementa la navigazione senza usare il NavigationView controllo . Se usi NavigationView, queste informazioni offrono utili conoscenze di base, ma dovresti usare le linee guida e gli esempi specifici nell'articolo NavigationView.

Pulsante Indietro

Per creare un pulsante Indietro, usa il controllo pulsante con lo stile NavigationBackButtonNormalStyle e posizionalo all'angolo in alto a sinistra dell'interfaccia dell'app (per ulteriori dettagli, vedi gli esempi di codice XAML seguenti).

Pulsante Indietro in alto a sinistra dell'interfaccia utente dell'app

<Page>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Button x:Name="BackButton"
                Style="{StaticResource NavigationBackButtonNormalStyle}"
                IsEnabled="{x:Bind Frame.CanGoBack, Mode=OneWay}" 
                ToolTipService.ToolTip="Back"/>

    </Grid>
</Page>

Se l'app ha una CommandBar superiore, posiziona il controllo nell'area Button.

<Page>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        
        <CommandBar>
            <CommandBar.Content>
                <Button x:Name="BackButton"
                        Style="{StaticResource NavigationBackButtonNormalStyle}"
                        IsEnabled="{x:Bind Frame.CanGoBack, Mode=OneWay}" 
                        ToolTipService.ToolTip="Back" 
                        VerticalAlignment="Top"/>
            </CommandBar.Content>
        
            <AppBarButton Icon="Delete" Label="Delete"/>
            <AppBarButton Icon="Save" Label="Save"/>
        </CommandBar>
    </Grid>
</Page>

Per ridurre al minimo gli elementi dell'interfaccia utente che si spostano nell'app, visualizzare un pulsante Indietro disabilitato quando non è presente alcun elemento nel backstack (IsEnabled="{x:Bind Frame.CanGoBack, Mode=OneWay}"). Tuttavia, se prevedi che l'applicazione non avrà mai un backstack, non devi visualizzare affatto il pulsante Indietro.

stato del pulsante Indietro

Ottimizzare per dispositivi e input diversi

Queste linee guida per la progettazione della navigazione all'indietro sono applicabili a tutti i dispositivi, ma gli utenti potranno trarre vantaggio se ottimizzi per diversi tipi di dispositivi e metodi di input. È consigliabile gestire gli eventi seguenti (oltre al pulsante Indietro Clic) per supportare gli input più comuni per lo spostamento indietro.

Evento Inserimento
CoreDispatcher.AcceleratorKeyActivated Alt+freccia sinistra,
VirtualKey.GoBack
SystemNavigationManager.BackRequested Windows + Cancella
Pulsante B del game pad,
Pulsante "Indietro" in modalità tablet
Pulsante Indietro hardware
CoreWindow.PointerPressed VirtualKey.XButton1
(come il pulsante Indietro trovato su alcuni mouse.)

Esempi di codice

In questa sezione viene illustrato come gestire lo spostamento indietro usando un'ampia gamma di input.

Pulsante Indietro e navigazione all'indietro

È necessario almeno gestire l'evento del pulsante Indietro Click e fornire il codice per eseguire la navigazione all'indietro. È anche consigliabile disabilitare il pulsante Indietro quando il backstack è vuoto.

Questo codice di esempio illustra come implementare il comportamento di spostamento indietro con un pulsante Indietro. Il codice risponde all'evento di fare clic sul pulsante per navigare. Il pulsante Indietro è abilitato o disabilitato nel metodo OnNavigatedTo , che viene chiamato quando si passa a una nuova pagina.

Il codice viene visualizzato per MainPage, ma questo codice viene aggiunto a ogni pagina che supporta lo spostamento indietro. Per evitare la duplicazione, è possibile inserire il codice relativo alla navigazione nella classe App nella pagina code-behind App.xaml.*.

<!-- MainPage.xaml -->
<Page x:Class="AppName.MainPage">
...
        <Button x:Name="BackButton" Click="BackButton_Click"
                Style="{StaticResource NavigationBackButtonNormalStyle}"
                IsEnabled="{x:Bind Frame.CanGoBack, Mode=OneWay}" 
                ToolTipService.ToolTip="Back"/>
...
<Page/>

Codice sottostante

// MainPage.xaml.cs
private void BackButton_Click(object sender, RoutedEventArgs e)
{
    App.TryGoBack();
}

// App.xaml.cs
//
// Add this method to the App class.
public static bool TryGoBack()
{
    Frame rootFrame = Window.Current.Content as Frame;
    if (rootFrame.CanGoBack)
    {
        rootFrame.GoBack();
        return true;
    }
    return false;
}
// MainPage.h
#include "App.h"

namespace winrt::AppName::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
        MainPage();
 
        void MainPage::BackButton_Click(IInspectable const&, RoutedEventArgs const&)
        {
            App::TryGoBack();
        }
    };
}

// App.h
#include "winrt/Windows.UI.Core.h"
#include "winrt/Windows.System.h"
#include "winrt/Windows.UI.Input.h"
#include "winrt/Windows.UI.Xaml.Input.h"
 
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::UI::Core;
using namespace Windows::UI::Input;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;

struct App : AppT<App>
{
    App();

    // ...

    // Perform back navigation if possible.
    static bool TryGoBack()
    {
        Frame rootFrame{ nullptr };
        auto content = Window::Current().Content();
        if (content)
        {
            rootFrame = content.try_as<Frame>();
            if (rootFrame.CanGoBack())
            {
                rootFrame.GoBack();
                return true;
            }
        }
        return false;
    }
};

Supporto chiavi di accesso

Il supporto della tastiera è fondamentale per garantire che le applicazioni funzionino in modo ottimale per gli utenti con competenze, capacità e aspettative diverse. È consigliabile supportare i tasti di scelta rapida per lo spostamento avanti e indietro, perché gli utenti che si basano su di essi si aspettano entrambi. Per maggiori informazioni, vedi le interazioni con la tastiera e gli acceleratori di tastiera .

I tasti di scelta rapida comuni per lo spostamento avanti e indietro sono ALT+Freccia DESTRA (avanti) e ALT+Freccia SINISTRA (indietro). Per supportare questi tasti per la navigazione, gestisci l'evento CoreDispatcher.AcceleratorKeyActivated. Gestisci un evento che avviene direttamente sulla finestra (anziché su un elemento della pagina), in modo che l'app risponda ai tasti di scelta rapida indipendentemente dal focus su un elemento.

Aggiungere il codice alla classe App per supportare i tasti di scelta rapida e lo spostamento in avanti, come illustrato di seguito. Si presuppone che il codice precedente per supportare il pulsante Indietro sia già stato aggiunto. È possibile visualizzare tutto il App codice insieme alla fine della sezione Esempi di codice.

// App.xaml.cs
// Add event handler in OnLaunched.
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    // ...
    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == null)
    {
        // ...
        // rootFrame.NavigationFailed += OnNavigationFailed;

        // Add support for accelerator keys. 
        // Listen to the window directly so the app responds
        // to accelerator keys regardless of which element has focus.
        Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated +=
            CoreDispatcher_AcceleratorKeyActivated;

        // ...

    }
}

// ...

// Add this code after the TryGoBack method added previously.
// Perform forward navigation if possible.
private bool TryGoForward()
{
    Frame rootFrame = Window.Current.Content as Frame;
    if (rootFrame.CanGoForward)
    {
        rootFrame.GoForward();
        return true;
    }
    return false;
}

// Invoked on every keystroke, including system keys such as Alt key combinations.
// Used to detect keyboard navigation between pages even when the page itself
// doesn't have focus.
private void CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher sender, AcceleratorKeyEventArgs e)
{
    // When Alt+Left are pressed navigate back.
    // When Alt+Right are pressed navigate forward.
    if (e.EventType == CoreAcceleratorKeyEventType.SystemKeyDown
        && (e.VirtualKey == VirtualKey.Left || e.VirtualKey == VirtualKey.Right)
        && e.KeyStatus.IsMenuKeyDown == true
        && !e.Handled)
    {
        if (e.VirtualKey == VirtualKey.Left)
        {
            e.Handled = TryGoBack();
        }
        else if (e.VirtualKey == VirtualKey.Right)
        {
            e.Handled = TryGoForward();
        }
    }
}
// App.cpp
void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    // ...
    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == nullptr)
    {
        // ...
        // rootFrame.NavigationFailed({ this, &App::OnNavigationFailed });

        // Add support for accelerator keys. 
        // Listen to the window directly so the app responds
        // to accelerator keys regardless of which element has focus.
        Window::Current().CoreWindow().Dispatcher().
            AcceleratorKeyActivated({ this, &App::CoreDispatcher_AcceleratorKeyActivated });

        // ...
    }
}

// App.h
struct App : AppT<App>
{
    App();

    // ...
    // Add this code after the TryGoBack method added previously.

private:
    // Perform forward navigation if possible.
    bool TryGoForward()
    {
        Frame rootFrame{ nullptr };
        auto content = Window::Current().Content();
        if (content)
        {
            rootFrame = content.try_as<Frame>();
            if (rootFrame.CanGoForward())
            {
                rootFrame.GoForward();
                return true;
            }
        }
        return false;
    }
 
 
    // Invoked on every keystroke, including system keys such as Alt key combinations.
    // Used to detect keyboard navigation between pages even when the page itself
    // doesn't have focus.
    void CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher const& /* sender */, AcceleratorKeyEventArgs const& e)
    {
        // When Alt+Left are pressed navigate back.
        // When Alt+Right are pressed navigate forward.
        if (e.EventType() == CoreAcceleratorKeyEventType::SystemKeyDown
            && (e.VirtualKey() == Windows::System::VirtualKey::Left || e.VirtualKey() == Windows::System::VirtualKey::Right)
            && e.KeyStatus().IsMenuKeyDown
            && !e.Handled())
        {
            if (e.VirtualKey() == Windows::System::VirtualKey::Left)
            {
                e.Handled(TryGoBack());
            }
            else if (e.VirtualKey() == Windows::System::VirtualKey::Right)
            {
                e.Handled(TryGoForward());
            }
        }
    }
};

Gestire le richieste di ritorno del sistema

I dispositivi Windows offrono vari modi in cui il sistema può passare una richiesta di spostamento indietro all'app. Alcuni modi comuni sono il pulsante B in un game pad, il tasto Windows + tasto Backspace o il pulsante Indietro del sistema in modalità Tablet; le opzioni esatte disponibili dipendono dal dispositivo.

È possibile supportare le richieste di back fornite dai tasti di sistema hardware e software registrando un listener per l'evento SystemNavigationManager.BackRequested.

Ecco il codice aggiunto alla classe App per supportare le richieste di ritorno fornite dal sistema. Si presuppone che il codice precedente per supportare il pulsante Indietro sia già stato aggiunto. È possibile visualizzare tutto il App codice insieme alla fine della sezione Esempi di codice.

// App.xaml.cs
// Add event handler in OnLaunced.
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    // ...
    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == null)
    {
        // ...
        // Add support for accelerator keys. 
        // ... (Previously added code.)

        // Add support for system back requests. 
        SystemNavigationManager.GetForCurrentView().BackRequested 
            += System_BackRequested;

        // ...

    }
}

// ...
// Handle system back requests.
private void System_BackRequested(object sender, BackRequestedEventArgs e)
{
    if (!e.Handled)
    {
        e.Handled = TryGoBack();
    }
}
// App.cpp
void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    // ...
    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == nullptr)
    {
        // ...
        // Add support for accelerator keys. 
        // ... (Previously added code.)

        // Add support for system back requests. 
        SystemNavigationManager::GetForCurrentView().
            BackRequested({ this, &App::System_BackRequested });

        // ...
    }
}

// App.h
struct App : AppT<App>
{
    App();

    // ...

private:
    // ...

    // Handle system back requests.
    void System_BackRequested(IInspectable const& /* sender */, BackRequestedEventArgs const& e)
    {
        if (!e.Handled())
        {
            e.Handled(TryGoBack());
        }
    }
};

Comportamento del tasto indietro del sistema per la compatibilità con le versioni precedenti

In precedenza, le app UWP usavano SystemNavigationManager.AppViewBackButtonVisibility per mostrare o nascondere un pulsante Indietro di sistema per lo spostamento indietro. Questo pulsante genera un evento SystemNavigationManager.BackRequested. Questa API continuerà a essere supportata per garantire la compatibilità con le versioni precedenti, ma non è più consigliabile usare il pulsante Indietro esposto da AppViewBackButtonVisibility. Devi invece fornire il pulsante Indietro in-app come descritto in questo articolo.

Se si continua a usare AppViewBackButtonVisibility, l'interfaccia utente di sistema visualizza il pulsante Indietro del sistema all'interno della barra del titolo. L'aspetto e le interazioni dell'utente per il pulsante Indietro sono invariati rispetto alle build precedenti.

pulsante Indietro della barra del titolo

Gestire i pulsanti di spostamento del mouse

Alcuni mouse forniscono pulsanti di spostamento hardware per lo spostamento avanti e indietro. È possibile gestire questi pulsanti del mouse gestendo l'evento CoreWindow.PointerPressed e verificando IsXButton1Pressed (indietro) o IsXButton2Pressed (avanti).

Ecco il codice aggiunto alla classe App per supportare la navigazione con il pulsante del mouse. Si presuppone che il codice precedente per supportare il pulsante Indietro sia già stato aggiunto. È possibile visualizzare tutto il App codice insieme alla fine della sezione Esempi di codice.

// App.xaml.cs
// Add event handler in OnLaunced.
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    // ...
    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == null)
    {
        // ...
        // Add support for system back requests. 
        // ... (Previously added code.)

        // Add support for mouse navigation buttons. 
        Window.Current.CoreWindow.PointerPressed += CoreWindow_PointerPressed;

        // ...

    }
}

// ...

// Handle mouse back button.
private void CoreWindow_PointerPressed(CoreWindow sender, PointerEventArgs e)
{
    // For this event, e.Handled arrives as 'true'.
    if (e.CurrentPoint.Properties.IsXButton1Pressed)
    {
        e.Handled = !TryGoBack();
    }
    else if (e.CurrentPoint.Properties.IsXButton2Pressed)
    {
        e.Handled = !TryGoForward();
    }
}
// App.cpp
void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    // ...
    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == nullptr)
    {
        // ...
        // Add support for system back requests. 
        // ... (Previously added code.)

        // Add support for mouse navigation buttons. 
        Window::Current().CoreWindow().
            PointerPressed({ this, &App::CoreWindow_PointerPressed });

        // ...
    }
}

// App.h
struct App : AppT<App>
{
    App();

    // ...

private:
    // ...

    // Handle mouse forward and back buttons.
    void CoreWindow_PointerPressed(CoreWindow const& /* sender */, PointerEventArgs const& e)
    {
        // For this event, e.Handled arrives as 'true'. 
        if (e.CurrentPoint().Properties().IsXButton1Pressed())
        {
            e.Handled(!TryGoBack());
        }
        else if (e.CurrentPoint().Properties().IsXButton2Pressed())
        {
            e.Handled(!TryGoForward());
        }
    }
};

Tutto il codice aggiunto alla classe App

// App.xaml.cs
//
// (Add event handlers in OnLaunched override.)
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    // ...
    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == null)
    {
        // ...
        // rootFrame.NavigationFailed += OnNavigationFailed;

        // Add support for accelerator keys. 
        // Listen to the window directly so the app responds
        // to accelerator keys regardless of which element has focus.
        Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated +=
            CoreDispatcher_AcceleratorKeyActivated;

        // Add support for system back requests. 
        SystemNavigationManager.GetForCurrentView().BackRequested 
            += System_BackRequested;

        // Add support for mouse navigation buttons. 
        Window.Current.CoreWindow.PointerPressed += CoreWindow_PointerPressed;

        // ...

    }
}

// ...

// (Add these methods to the App class.)
public static bool TryGoBack()
{
    Frame rootFrame = Window.Current.Content as Frame;
    if (rootFrame.CanGoBack)
    {
        rootFrame.GoBack();
        return true;
    }
    return false;
}

// Perform forward navigation if possible.
private bool TryGoForward()
{
    Frame rootFrame = Window.Current.Content as Frame;
    if (rootFrame.CanGoForward)
    {
        rootFrame.GoForward();
        return true;
    }
    return false;
}

// Invoked on every keystroke, including system keys such as Alt key combinations.
// Used to detect keyboard navigation between pages even when the page itself
// doesn't have focus.
private void CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher sender, AcceleratorKeyEventArgs e)
{
    // When Alt+Left are pressed navigate back.
    // When Alt+Right are pressed navigate forward.
    if (e.EventType == CoreAcceleratorKeyEventType.SystemKeyDown
        && (e.VirtualKey == VirtualKey.Left || e.VirtualKey == VirtualKey.Right)
        && e.KeyStatus.IsMenuKeyDown == true
        && !e.Handled)
    {
        if (e.VirtualKey == VirtualKey.Left)
        {
            e.Handled = TryGoBack();
        }
        else if (e.VirtualKey == VirtualKey.Right)
        {
            e.Handled = TryGoForward();
        }
    }
}

// Handle system back requests.
private void System_BackRequested(object sender, BackRequestedEventArgs e)
{
    if (!e.Handled)
    {
        e.Handled = TryGoBack();
    }
}

// Handle mouse back button.
private void CoreWindow_PointerPressed(CoreWindow sender, PointerEventArgs e)
{
    // For this event, e.Handled arrives as 'true'.
    if (e.CurrentPoint.Properties.IsXButton1Pressed)
    {
        e.Handled = !TryGoBack();
    }
    else if (e.CurrentPoint.Properties.IsXButton2Pressed)
    {
        e.Handled = !TryGoForward();
    }
}


// App.cpp
void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    // ...
    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == nullptr)
    {
        // ...
        // rootFrame.NavigationFailed({ this, &App::OnNavigationFailed });

        // Add support for accelerator keys. 
        // Listen to the window directly so the app responds
        // to accelerator keys regardless of which element has focus.
        Window::Current().CoreWindow().Dispatcher().
            AcceleratorKeyActivated({ this, &App::CoreDispatcher_AcceleratorKeyActivated });

        // Add support for system back requests. 
        SystemNavigationManager::GetForCurrentView().
            BackRequested({ this, &App::System_BackRequested });

        // Add support for mouse navigation buttons. 
        Window::Current().CoreWindow().
            PointerPressed({ this, &App::CoreWindow_PointerPressed });

        // ...
    }
}

// App.h
#include "winrt/Windows.UI.Core.h"
#include "winrt/Windows.System.h"
#include "winrt/Windows.UI.Input.h"
#include "winrt/Windows.UI.Xaml.Input.h"
 
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::UI::Core;
using namespace Windows::UI::Input;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;

struct App : AppT<App>
{
    App();

    // ...

    // Perform back navigation if possible.
    static bool TryGoBack()
    {
        Frame rootFrame{ nullptr };
        auto content = Window::Current().Content();
        if (content)
        {
            rootFrame = content.try_as<Frame>();
            if (rootFrame.CanGoBack())
            {
                rootFrame.GoBack();
                return true;
            }
        }
        return false;
    }
private:
    // Perform forward navigation if possible.
    bool TryGoForward()
    {
        Frame rootFrame{ nullptr };
        auto content = Window::Current().Content();
        if (content)
        {
            rootFrame = content.try_as<Frame>();
            if (rootFrame.CanGoForward())
            {
                rootFrame.GoForward();
                return true;
            }
        }
        return false;
    }
  
    // Invoked on every keystroke, including system keys such as Alt key combinations.
    // Used to detect keyboard navigation between pages even when the page itself
    // doesn't have focus.
    void CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher const& /* sender */, AcceleratorKeyEventArgs const& e)
    {
        // When Alt+Left are pressed navigate back.
        // When Alt+Right are pressed navigate forward.
        if (e.EventType() == CoreAcceleratorKeyEventType::SystemKeyDown
            && (e.VirtualKey() == Windows::System::VirtualKey::Left || e.VirtualKey() == Windows::System::VirtualKey::Right)
            && e.KeyStatus().IsMenuKeyDown
            && !e.Handled())
        {
            if (e.VirtualKey() == Windows::System::VirtualKey::Left)
            {
                e.Handled(TryGoBack());
            }
            else if (e.VirtualKey() == Windows::System::VirtualKey::Right)
            {
                e.Handled(TryGoForward());
            }
        }
    }

    // Handle system back requests.
    void System_BackRequested(IInspectable const& /* sender */, BackRequestedEventArgs const& e)
    {
        if (!e.Handled())
        {
            e.Handled(TryGoBack());
        }
    }

    // Handle mouse forward and back buttons.
    void CoreWindow_PointerPressed(CoreWindow const& /* sender */, PointerEventArgs const& e)
    {
        // For this event, e.Handled arrives as 'true'. 
        if (e.CurrentPoint().Properties().IsXButton1Pressed())
        {
            e.Handled(!TryGoBack());
        }
        else if (e.CurrentPoint().Properties().IsXButton2Pressed())
        {
            e.Handled(!TryGoForward());
        }
    }
};

Ripresa

Quando l'utente passa a un'altra app e torna alla tua app, ti consigliamo di tornare all'ultima pagina nella cronologia di navigazione.