天天看點

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

操縱導航堆棧

有時需要改變正常的面向堆棧的導航流程。例如,假設頁面需要來自使用者的一些資訊,但首先它導航到提供一些指令或免責聲明的頁面,然後從那裡導航到實際擷取資訊的頁面。當使用者完成并傳回時,您将希望跳過包含說明或免責聲明的頁面。該頁面應從導航堆棧中删除。

這是一個類似的例子:假設使用者正在與擷取某些資訊的頁面進行互動,然後想要傳回上一頁。但是,程式檢測到此資訊出現問題,需要在單獨的頁面上進行擴充讨論。該程式可以将新頁面插入導航堆棧以提供該讨論。

或者某個頁面序列可能以标記為“轉到首頁”的按鈕結束,并且在導航回首頁時可以簡單地跳過其間的所有頁面。

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對象。

繼續閱讀