第二十四章:页面导航(七)

操纵导航堆栈
有时需要改变正常的面向堆栈的导航流程。例如,假设页面需要来自用户的一些信息,但首先它导航到提供一些指令或免责声明的页面,然后从那里导航到实际获取信息的页面。当用户完成并返回时,您将希望跳过包含说明或免责声明的页面。该页面应从导航堆栈中删除。
这是一个类似的例子:假设用户正在与获取某些信息的页面进行交互,然后想要返回上一页。但是,程序检测到此信息出现问题,需要在单独的页面上进行扩展讨论。该程序可以将新页面插入导航堆栈以提供该讨论。
或者某个页面序列可能以标记为“转到主页”的按钮结束,并且在导航回主页时可以简单地跳过其间的所有页面。
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对象。

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