2015/10/19

UWP - 處理 back-navigation event 機制

UWP - 處理 back-navigation event 機制

過去開發 UAP 的時候對於用戶按下 Back 鍵,App 會被觸發  Frame.GoBack() 與 Page.OnNavigatedFrom(),在 App 處理 Phone 的時候會有這樣的代碼:(至於 Windows RT App,則是在畫面上加入一個 Back 鈕提供 Back 任務)
   1: Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
   2:  
   3: /// <summary>
   4: /// Invoked when the hardware back button is pressed. For Windows Phone only.
   5: /// </summary>
   6: /// <param name="sender">Instance that triggered the event.</param>
   7: /// <param name="e">Event data describing the conditions that led to the event.</param>
   8: private void HardwareButtons_BackPressed(object sender, Windows.Phone.UI.Input.BackPressedEventArgs e)
   9: {
  10:     // do something and go bak
  11:     if (Window.Current.Content.GetType() == typeof(Frame))
  12:     {
  13:         Frame rootFrame = Window.Current.Content as Frame;
  14:         rootFrame.GoBack();
  15:     }}
  16: }


到了 UWP 開發時,需要自己按照 App 預計支援的 device families 來處理這個 Back 事件,那如果沒有 Back 實體按鍵要怎麽處理?

針對這兩個問題分別説明:

1. 使用 Adaptive code 來判別 Mobile 設備是否支援 Back 實體按鈕
   1: protected override void OnLaunched(LaunchActivatedEventArgs e)
   2: {
   3:     // 利用 ApiInformation.IsTypePresent 判斷是否支援 Back 實體按鍵
   4:     bool isHardwareButtonsAPIPresent = 
   5:         Windows.Foundation.Metadata.ApiInformation.IsTypePresent(
   6:             "Windows.Phone.UI.Input.HardwareButtons");
   7:  
   8:     // 如果有加以注冊 HardwareButtons.CameraPressed 
   9:     // 要記得先加入 Windows Mobile Extensions for the UWP
  10:     if (isHardwareButtonsAPIPresent)
  11:     {
  12:         Windows.Phone.UI.Input.HardwareButtons.BackPressed 
  13:             += HardwareButtons_BackPressed;  
  14:     }
  15: }
ApiInformation class
     用來檢查要使用的 member, type, 或是 API 是否被支援,讓你能安全 API 呼叫跨多種設備。幾個常用的 Methods:

Method Description
IsTypePresent Returns true or false to indicate whether a specified type is present.
IsApiContractPresent(String,UInt16) Returns true or false to indicate whether the API contract with the specified name and major version number is present.
IsEventPresent Returns true or false to indicate whether a specified event is present for a specified type.
IsMethodPresent(String,String) Returns true or false to indicate whether a specified method is present for a specified type.
IsMethodPresent(String,String,UInt32) Returns true or false to indicate whether a specified method overload with the specified number of input parameters is present for a specified type.


HardwareButtons class

     針對 Phone 主要有幾種實體按鍵事件可以處理:

Event Description
BackPressed Occurs when the user presses the hardware Back button.
CameraHalfPressed Occurs when the user presses the hardware camera button halfway.
CameraPressed Occurs when the user presses the hardware camera button.
CameraReleased Occurs when the user releases the hardware camera button.

 
2. 使用 SystemNavigationManager  在 App.xaml.cs 時取得 CurrentView 并且注冊 BackRequest 事件

2-1. 在 OnLaunched 加入對 rootFrame.Navigated 事件的注冊與加入 SystemNavigationManager 注冊 BackReqeust 事件:
   1: protected override void OnLaunched(LaunchActivatedEventArgs e)
   2: {
   3:     Frame rootFrame = Window.Current.Content as Frame;
   4:  
   5:     // Do not repeat app initialization when the Window already has content,
   6:     // just ensure that the window is active
   7:     if (rootFrame == null)
   8:     {
   9:         // Create a Frame to act as the navigation context and navigate to the first page
  10:         rootFrame = new Frame();
  11:  
  12:         rootFrame.NavigationFailed += OnNavigationFailed;
  13:         // 加入該事件,用來判讀是否要顯示 Back 按鈕
  14:         rootFrame.Navigated += RootFrame_Navigated;
  15:  
  16:         if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
  17:         {
  18:             //TODO: Load state from previously suspended application
  19:         }
  20:  
  21:         // Place the frame in the current Window
  22:         Window.Current.Content = rootFrame;
  23:     }
  24:  
  25:     if (rootFrame.Content == null)
  26:     {
  27:         // When the navigation stack isn't restored navigate to the first page,
  28:         // configuring the new page by passing required information as a navigation
  29:         // parameter
  30:         rootFrame.Navigate(typeof(MainPage), e.Arguments);
  31:     }
  32:     // Ensure the current window is active
  33:     Window.Current.Activate();
  34:     
  35:     // 宣告要處理 Back 事件
  36:     SystemNavigationManager.GetForCurrentView().BackRequested += App_BackRequested;
  37: }

2-2. 處理 BackRequest 事件:
   1:  
   2: private void App_BackRequested(object sender, BackRequestedEventArgs e)
   3: {
   4:     Frame rootFrame = Window.Current.Content as Frame;
   5:     if (rootFrame.CanGoBack)
   6:     {
   7:         e.Handled = true;
   8:         rootFrame.GoBack();
   9:     }
  10: }

2-3. 處理在 rootFrame.Navigated 時判斷是否要顯示 Back 按鈕:
   1:  
   2: private void RootFrame_Navigated(object sender, NavigationEventArgs e)
   3: {
   4:     // Each time a navigation event occurs, update the Back button's visibility
   5:     SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
   6:         ((Frame)sender).CanGoBack ?
   7:         AppViewBackButtonVisibility.Visible :
   8:         AppViewBackButtonVisibility.Collapsed;
   9: }

SystemNavigationManager
    提供方法回應系統發出的 back-navigation events。讓開發人員可以處理:
  • user 按下 hardware button 或是系統提供的 back button
  • gestures 造成的 back
  • voice commands 觸發的 back

主要元素如下:

Type Name Description
Event BackRequested Occurs when the user invokes the system provided button, gesture, or voice command for back-navigation.
Method GetForCurrentView Returns the SystemNavigationManager object associated with the current window.
Property AppViewBackButtonVisibility Read/write,Gets or sets a value that indicates whether a back button is shown in the system UI.

如果以 Win10 系統來看, back button 就是出現在 App 視窗左上角。

根據<Handling the Back Button in Windows 10 UWP Apps>的説明,Windows.UI.Core.SystemNavigationManager 有兩個重要的任務:
  • 提供給 App 運行在沒有實體 Back 按鍵上時,可以提供畫面出現一個  digital back button 讓用戶可以返回上一個畫面;
  • 允許 App 去注冊處理 Back 按鈕(software or hardware)的 click 事件,不需要爲了單純處理 Back 按鈕而加入真個 extension SDKs;

[注意]
  • 同時注冊了  Windows.Phone.UI.Input.HardwareButtons.BackPressed 與  SystemNavigationManager.GetForCurrentView().BackRequested,

    會先觸發 HardwareButtons 的事件才會輪到 BackRequested,如果 HardwareButtons 加了 e.Handled = true;  那麽 BackRequested 就不會收到。
  • BackRequested 衹有允許 foreground app 收到事件。
  • If the device doesn't provide any back-navigation button, gesture, or command, the event is not raised.
======
這篇單純筆記,因爲很容易忘記要做 Back 鍵的處理,然後再去找到對應的 Namespace 來判斷,所以特別記錄該篇方便查詢。


References
Handling the Back Button in Windows 10 UWP Apps
API Convergence Gets Real in Windows 10
Developing Universal Windows Apps with C# and XAML
Navigation design basics for Universal Windows Platform (UWP) apps (重要)
Guidelines for back buttons (重要)
Navigation (重要)
Universal Windows Apps with XAML and C# Unleashed: Threading, Windows, and Pages
Get Ready for Windows 10: Learning Universal Windows App Development
Developing Universal Windows Apps with C# and XAML

沒有留言:

張貼留言