XamarinForms 系列課程

特別說明

2018/04/01

Part II Xamarin.Forms 的頁面導航 Page Navigation 之有無強制回應 Modal 對話窗和導航工具列 NavigationPage 的體驗

在上一篇 
Xamarin.Forms 的頁面導航Page Navigation 之有無強制回應Modal 對話窗和導航工具列NavigationPage 的體驗
 文章中,當我們使用了 Modal 模式進行導航功能的時候,由於在每個導航過去的頁面,並沒有任何按鈕可以讓我們返回上一頁,因此,當時測試的時候,是在 Android 模擬器下,使用實體回上頁按鈕,使得應用程式可以回上頁;不過,當在 iOS 環境下,並沒有實體回上頁的按鈕,此時就會發生問題。
在這篇文章中,將會延續剛剛提到的文章,繼續來進行探討關於有強制回應 Modal 的導航上的問題,那就是,若我們使用了強制回應 Modal 進行導航到新頁面,不過,該新頁面又有使用了 NavigationPage,這個時候,若我們已經導航過去了,您將會發現,在這個時間點,您是無法使用 _navigationService.GoBackAsync(); 這樣的敘述,讓應用程式回到上一頁,不過,您卻發現到使用了實體回上頁按鈕,卻可以強制回到上頁,對於這樣的問題,我們該如何進行因應呢?
首先,我們需要擴充 
Xamarin.Forms 的頁面導航Page Navigation 之有無強制回應Modal 對話窗和導航工具列NavigationPage 的體驗
 文章中的範例專案程式碼,這個專案程式碼可以 這裡 看到

修正測試專案

在上一篇文章中,若您點選了 [導航到下一頁(有強制回應且有導航頁面)] 倒數第二個按鈕,此時,我們將會使用 _navigationService.NavigateAsync("NavigationPage/Page1Page", null, true); 這樣的敘述,進行頁面導航,不過,我們發現到了,這個時候,我們有在一次使用了 NavigationPage 這個頁面,並且用於此次新的頁面導航中,不過,若我們有再 Page1 頁面中放一個按鈕,當使用按下了這個按鈕,我們就會執行 _navigationService.GoBackAsync(); 這樣的敘述,因此,您將會發現到,按下的這個頁面中的按鈕,卻無法幫助我們回到上一頁,為什麼會有這樣的現象呢?
經過了除錯測試,我們可以確定我們真的有執行了 _navigationService.GoBackAsync(); ,只不過很可惜的,頁面一樣停留在 Page1 中,無法回到主頁面中。
舊的主頁面
現在,我們將這個測試專案修正成為如下截圖內容,其中,我們將原先 [導航到下一頁(有強制回應且有導航頁面)] 這個按鈕,修正名稱成為 [導航到下一頁(有強制回應且有導航頁面)(回上頁按鈕程式碼會失效)],並且另外三個按鈕:[導航到下一頁(有強制回應且有導航頁面)(PopModalAsync)] , [導航到下兩頁(有強制回應且有導航頁面)(逐頁返回)] , [導航到下兩頁(有強制回應且有導航頁面)(全部返回)]
  • 導航到下一頁(有強制回應且有導航頁面)(回上頁按鈕程式碼會失效)
    當按下這個按鈕,將會使用 NavigationPage/Page1Page 這個導航路徑進行頁面導航,也就是 Home -> Page1 (實際上在 Xamarin.Forms 的內部中,紀錄的是 Home -> NavigationPage -> Page1)
  • 導航到下一頁(有強制回應且有導航頁面)(PopModalAsync)
    當按下這個按鈕,將會使用 NavigationPage/Page3Page 這個導航路徑進行頁面導航,也就是 Home -> Page3 (實際上在 Xamarin.Forms 的內部中,紀錄的是 Home -> NavigationPage -> Page3)
  • 導航到下兩頁(有強制回應且有導航頁面)(逐頁返回)
    當按下這個按鈕,將會使用 NavigationPage/Page3Page/Page2Page 這個導航路徑進行頁面導航,也就是 Home -> Page3 -> Page2 (實際上在 Xamarin.Forms 的內部中,紀錄的是 Home -> NavigationPage -> Page1 -> Page2)
  • 導航到下兩頁(有強制回應且有導航頁面)(全部返回)
    當按下這個按鈕,將會使用 NavigationPage/Page3Page/Page4Page 這個導航路徑進行頁面導航,也就是 Home -> Page3 -> Page4 (實際上在 Xamarin.Forms 的內部中,紀錄的是 Home -> NavigationPage -> Page3 -> Page4)
舊的主頁面
另外,我們也追加了兩個新的頁面 Page3, Page4,這兩個頁面與 Page1 , Page2 的差別在於當在這些 ContentPage 頁面中,按下了 Back 按鈕之,前者使用了 PopModalAsync 方法來回上頁,而後者使用了 GoBackAsync 方法來回上頁。

檢視測試結果 導航到下一頁(有強制回應且有導航頁面)(回上頁按鈕程式碼會失效)

當我們導航到了 Page1 (Home -> Page1),並且按下頁面中間的 Back 按鈕,我們發現到這個時候,我們是無法正常回到了首頁;這是因為我們在導航路徑中使用了 NavigationPage 在導航路徑中。
Page1

檢視測試結果 導航到下一頁(有強制回應且有導航頁面)(PopModalAsync)

當我們導航到了 Page1 (Home -> Page3),並且按下頁面中間的 Back 按鈕,現在我們可以正常的回到首頁了,這是因為我們在按下這個按鈕的 DelegateCommand 委派方法中,使用了底下的程式碼,在這裡,我們透過了靜態屬性 App.Current 取得了整個系統的 App 類別的物件,接著,透過 MainPage 屬性,取得正在顯示的頁面物件,如此,我們就可以呼叫 ContentPage 頁面的 Navigation 屬性內的 PopModalAsync 方法,讓系統可以關閉強制回應的頁面。所以,在這樣的設計模式下,不論使用者使用實體退回按鈕或者頁面中的 Back 按鈕,都可以正常回上頁。
會有這樣的結果,這是因為 ContentPage 頁面的 Navigation 屬性是屬於 Xamarin.Forms.INavigation 介面實作,在 Xamarin.Forms.INavigation 介面中,宣告了兩個屬性 ModalStack 與 NavigationStack 。因為我們現在使用了強制回應的導航模式,因此,將會進入到 ModalStack 堆疊內,可能是 Prism 導航服務上有些狀況,無法正常取消強制回應的顯示模式,關於更多關於這方面的內容,可以查看 Prism PageNavigationService 原始碼;因此,我們需要使用 Xamarin.Forms.INavigation.PopModalAsync/) 來關閉強制回應的導航模式。
C# CSharp
GoBackCommand = new DelegateCommand(async () =>
{
    var fooPage = App.Current.MainPage;
    var fooNavigationStack = fooPage.Navigation.NavigationStack;
    var fooModalStack = fooPage.Navigation.ModalStack;
    await fooPage.Navigation.PopModalAsync();
});
Page3

檢視測試結果 導航到下兩頁(有強制回應且有導航頁面)(逐頁返回)

現在,讓我們來測試強制回應的深度導航,當我們導航到了 Page1 (Home -> Page3 -> Page2),我們可以按下在 Page2 頁面中間的 Back 按鈕,此時,該 Back 按鈕會使用 Prism 導航服務來回上頁;現在在 Page3 中,點選頁面中間的 Back 按鈕,該 Back 按鈕會使用關閉強制回應導航模式,並且回到了首頁了。
Page3 > Page4

檢視測試結果 導航到下兩頁(有強制回應且有導航頁面)(全部返回)

現在,讓我們來測試強制回應的深度導航,當我們導航到了 Page1 (Home -> Page3 -> Page4),我們可以按下在 Page4 頁面中間的 Back 按鈕,此時,該 Back 按鈕會使用 關閉強制回應導航模式,也就是會強制關閉這一連串強制回應的深度導航了,並且直接回到了首頁了,因此,您再也看不到 Page3 的顯示內容了。
Page3 > Page4

回顧上篇文章




+

沒有留言:

張貼留言