第二十四章:頁面導航(七)

操縱導航堆棧
有時需要改變正常的面向堆棧的導航流程。例如,假設頁面需要來自用戶的一些信息,但首先它導航到提供一些指令或免責聲明的頁面,然後從那裏導航到實際獲取信息的頁面。當用戶完成並返回時,您將希望跳過包含說明或免責聲明的頁面。該頁面應從導航堆棧中刪除。
這是一個類似的例子:假設用戶正在與獲取某些信息的頁面進行交互,然後想要返回上一頁。但是,程序檢測到此信息出現問題,需要在單獨的頁面上進行擴展討論。該程序可以將新頁面插入導航堆棧以提供該討論。
或者某個頁面序列可能以標記爲“轉到主頁”的按鈕結束,並且在導航回主頁時可以簡單地跳過其間的所有頁面。
INavigation接口定義了所有這三種情況的方法。它們被命名爲RemovePage,InsertPageBefore和PopToRootAsync。
StackManipulation程序以非常抽象的方式演示了這三種方法。該程序由五個僅代碼頁面組成,分別名爲PageA,PageB,PageBAlternative,PageC和PageD。每個頁面都設置其Title屬性以標識自身。
PageA有一個導航到PageB的按鈕:

public class PageA : ContentPage
{
    public PageA()
    {
        Button button = new Button
        {
            Text = "Go to Page B",
            FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Button)),
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center
        };
        button.Clicked += async (sender, args) =>
        {
            await Navigation.PushAsync(new PageB());
        };
        Title = "Page A";
        Content = new button;
    }
}

PageB類似,只是導航到PageC。 PageBA替代與PageB相同,只是它將自己標識爲“Page B Alt”。 PageC有一個按鈕可以導航到PageD,而PageD有兩個按鈕:

public class PageD : ContentPage
{
    public PageD()
    {
        // Create Button to go directly to PageA.
        Button homeButton = new Button
        {
            Text = "Go Directly to Home",
            FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Button)),
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };
        homeButton.Clicked += async (sender, args) =>
        {
            await Navigation.PopToRootAsync();
        };
        // Create Button to swap pages.
        Button swapButton = new Button
        {
            Text = "Swap B and Alt B",
            FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Button)),
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };
        swapButton.Clicked += (sender, args) =>
        {
            IReadOnlyList<Page> navStack = Navigation.NavigationStack;
            Page pageC = navStack[navStack.Count - 2];
            Page existingPageB = navStack[navStack.Count - 3];
            bool isOriginal = existingPageB is PageB;
            Page newPageB = isOriginal ? (Page)new PageBAlternative() : new PageB();
            // Swap the pages.
            Navigation.RemovePage(existingPageB);
            Navigation.InsertPageBefore(newPageB, pageC);
            // Finished: Disable the Button.
            swapButton.IsEnabled = false;
        };
        Title = "Page D";
        Content = new StackLayout
        {
            Children =
            {
                homeButton,
                swapButton
            }
        };
    }
}

標記爲Go Directly to Home的按鈕具有一個調用PopToRootAsync的Clicked處理程序。 這會導致程序跳回到PageA並有效地清除所有中間頁面的導航堆棧。
標記爲Swap B和Alt B的按鈕稍微複雜一些。 此按鈕的Clicked處理程序將PageB替換爲導航堆棧中的PageBAlternative(反之亦然),因此當您返回頁面時,您將遇到不同的頁面B.以下是Clicked處理程序的執行方式:
在單擊Button時,NavigationStack有四個索引爲0,1,2和3的項。這四個索引對應於PageA(PageB(或PageBA替代),PageC和PageD類型的堆棧中的對象。 處理程序訪問NavigationStack以獲取這些實際實例:

IReadOnlyList<Page> navStack = Navigation.NavigationStack;
Page pageC = navStack[navStack.Count - 2];
Page existingPageB = navStack[navStack.Count - 3];

現有的Page對象可能是Page或Page Alternative類型,因此創建另一個類型的newPageB對象:

bool isOriginal = existingPageB is PageB;
Page newPageB = isOriginal ? (Page)new PageBAlternative() : new PageB();

接下來的兩個語句從導航堆棧中刪除existingPageB對象,然後在pageC之前插入newPageB對象,有效地交換頁面:

// Swap the pages.
Navigation.RemovePage(existingPageB);
Navigation.InsertPageBefore(newPageB, pageC);

顯然,第一次單擊此按鈕時,existingPageB將是一個PageB對象,newPageB將是一個PageBA替代對象,但您可以返回到PageC或PageBA替代,然後再向前導航到PageD。 再次單擊該按鈕將使用PageB對象替換PageBAlternative對象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章