在前面已經有兩篇文章探討 Xamarin.Forms 頁面導航之相關應用 Xamarin.Forms 的頁面導航Page Navigation 之有無強制回應Modal 對話窗和導航工具列NavigationPage 的體驗 與 Part II Xamarin.Forms 的頁面導航 Page Navigation 之有無強制回應 Modal 對話窗和導航工具列 NavigationPage 的體驗 的兩篇文章,現在,我們繼續來探討頁面導航的應用,那就是我們要如何在進行頁面導航的過程中,需要調整導航堆疊的內容,以便當使用者要返回到上個頁面時候,可以跳到更前面的頁面。
了解更多關於 [Xamarin.Android] 的使用方式
了解更多關於 [Xamarin.iOS] 的使用方式
了解更多關於 [Xamarin.Forms] 的使用方式
了解更多關於 [Hello, Android:快速入門] 的使用方式
了解更多關於 [Hello, iOS – 快速入門] 的使用方式
了解更多關於 [Xamarin.Forms 快速入門] 的使用方式
在這裡,我們將要模擬一個日常開發專案中,經常會遇到的情境,我們需要做到這樣的頁面導航情境,在這裡我們有三個頁面,專案啟動之後,會先顯示 MainPage,在這個螢幕上,使用者可以在 MainPage 頁面點選按鈕,此時,就會導航到 DetailPage 頁面,而在這個時候,若使用點選了 DetailPage 頁面上的按鈕,系統將會使用 Modal 強制回應模式進行頁面導航到 EditPage;由於我們導航到 EditPage 採用的 Modal 強制回應的模式,因此,在這個頁面上沒有任何的導航工具列,所以,使用者若要回到前一個頁面,緊能夠點選該頁面上的按鈕,不過,當使用者點選這個按鈕之後,將會跳過 DetailPage,而是回到 MainPage 頁面(請不要使用絕對導航模式,重啟新的導航到 MainPage);另外,您將會注意到,在 Android 平台上,EditPage 頁面雖然沒有了左上角的軟體回上頁按鈕,可是,當我們點選了實體回上頁按鈕,此時應用程式卻回到了 DetailPage,這並不是我們所要看到的,因此,我們也要解決此一問題。
NavigationPage -> MainPage -> DetailPage --(使用 Modal)--> EditPage
從導航堆疊中移除頁面節點
首先,我們要來修正 EditPage ViewModel 的按鈕 DelegateCommand 的委派方法,透過 App.Current.MainPage 屬性,取得現在 Xamarin.Forms 正在顯示的頁面物件,接著,就可以透過 INavigation 介面的實作物件 (從 ContentPage.Navigation 屬性來取得),進一步取得 NavigationStack 導航堆疊物件,有了導航堆疊 Navigation Stack,我們就可以透過了 Navigation.RemovePage 方法,把導航堆疊中的某個頁面,從導航堆疊中移除。若您想要在導航堆疊中插入某個新的頁面,也可以透過 InsertPageBefore 方法來做到。
經過這樣的修正之後,您將會看到當您呼叫了 _navigationService.GoBackAsync 方法之後,將會依照您調整過的導航堆疊,返回到導航堆疊中的最後一個頁面。
GoBackPageCommand = new DelegateCommand(async () =>
{
var fooPage = App.Current.MainPage;
var fooNavigationStack = fooPage.Navigation.NavigationStack;
var fooModalStack = fooPage.Navigation.ModalStack;
var fooRemovePageNode = fooNavigationStack[fooNavigationStack.Count - 1];
fooPage.Navigation.RemovePage(fooRemovePageNode);
await _navigationService.GoBackAsync() ;
});
最後,我們還需要解決另外一個問題,那就是如何在 EditPage 頁面中,關閉實體回上頁按鈕的功能,想要做到這樣的需求,您需要在 EditPage 的 Code Behind 程式碼中,覆寫 Override 這個方法 OnBackButtonPressed,在這個方法我們需要回傳 true 布林值,這樣,就可以在這個頁面,把實體回上頁按鈕關閉起來了。
protected override bool OnBackButtonPressed()
{
return true;
}