【问题标题】:Xamarin Forms Shell - Navigation to old navigation stack rather than flyout pageXamarin Forms Shell - 导航到旧导航堆栈而不是弹出页面
【发布时间】:2022-01-15 17:52:43
【问题描述】:

我的 Xamarin Forms Shell 应用程序出现问题。我不确定这是错误还是预期的行为,有人可以指出正确的方向。

我有一个在 Visual Shell Hierarchy 中有 2 个页面的应用程序:

搜索和历史记录

<FlyoutItem Title="Search" Icon="search.png">
    <Tab Title="Search">
        <ShellContent Route="searchpage">
            <views:SearchPage />
        </ShellContent>
    </Tab>
</FlyoutItem>
<FlyoutItem Title="History" Icon="history.png">
    <Tab Title="History">
        <ShellContent>
            <views:HistoryPage />
        </ShellContent>
    </Tab>
</FlyoutItem>

还有几个页面(我们称它们为 PageA、PageB 和 PageC)是这样注册的:

Routing.RegisterRoute("PageA", typeof(PageA));    
Routing.RegisterRoute("PageB", typeof(PageB));    
Routing.RegisterRoute("PageC", typeof(PageC)); (Oops, I should probably use nameof here)

无论如何,我从搜索页面开始并导航到 PageA,如下所示:

Shell.Current.GoToAsync("PageA");

因为 PageA 不在视觉层次结构中,这给了我一个像这样的导航堆栈:

"//searchpage/PageA"

使用相同的相对导航方法,我导航到 PageB 然后是 PageC,所以我的导航堆栈是这样的:

"//searchpage/PageA/PageB/PageC"

从PageC,我使用弹出菜单导航到历史,历史页面打开正常。

现在在历史页面上,我再次使用弹出菜单并单击“搜索”标签

但我没有按预期被带到搜索页面,我被带回 PageC(带回我之前的导航堆栈)。

如果我再次使用弹出菜单并单击“搜索”选项卡,从该页面 (PageC) 中,它会正确导航到“搜索”页面。

当我从浮出控件中选择“搜索”选项卡时,它应该如何工作以及如何阻止它导航到 PageC?

谢谢

(ps - 我目前使用的是 Xamarin Forms 4.7)

【问题讨论】:

  • official sample project的行为相同
  • 您好,这似乎是正常现象。切换弹出项时,不会改变每个项的堆叠顺序。它需要用户手动操作。但是第二次,shell 可能会清除堆栈。
  • 另外,如果使用Shell.Current.GoToAsync,下一页将不会显示FlyoutIcon菜单。因此,您可以从 PageC 分享如何使用弹出菜单导航到历史记录的代码。
  • @Craig 但是,我找不到一种方法来覆盖 flayout 项目的单击事件。也许您可以在 Github here 中提交功能请求。然后会有来自微软的工程师来了解需求。如果他们接受此功能请求,他们将在下一版本的 xamrin 表单中更新此功能。如果您已提交,请记得在此处分享链接。我也会在那里跟进。
  • @JuniorJiang-MSFT 是的,我会为此提交功能请求,完成后我会分享链接。感谢您的帮助。

标签: xamarin xamarin.forms


【解决方案1】:

对于那些仍在寻找答案的人,Damir's Corner的答案

await Shell.Current.GoToAsync($"///{tag}", false); //Checks the Navigation Stack Downward

上面的代码检查当前的导航堆栈,并向下搜索(或导航堆栈内部)的路由标记,然后用找到的路由替换整个堆栈。

希望这对那些正在寻找答案的人有所帮助。

【讨论】:

    【解决方案2】:

    当在不同的选项卡之间跳转(以及通过这样做不同的导航堆栈)时,Williams 解决方案(Damir's Corner)对我有用。

    我的场景:

    • Tab1 -> ListPage -> DetailsPage
    • Tab2 -> CreateStep1Page -> CreateStep2Page

    在 CreateSpecificPage 中保存条目后,我导航了两次:

    await Shell.Current.GoToAsync($"///{nameof(CreateStep1Page)}", false);
    await Shell.Current.GoToAsync($"///{nameof(ListPage)}/{nameof(DetailsPage)}", true);
    

    【讨论】:

      【解决方案3】:

      我会在 5 分钟后将此作为功能请求提出,但我已找到解决此问题的方法。

      1. 我将最后一页 (PageC) 设为 Root 页面并将其从我的 Routes 脚本中删除。我通过将以下内容添加到 AppShell.Xaml 来做到这一点,如下所示:

        <ShellItem Route="PageC">
            <ShellContent ContentTemplate="{DataTemplate views:PageC}" />
        </ShellItem>
        
        and removing this code:
        Routing.RegisterRoute("PageC", typeof(PageC));
        
      2. 现在当导航到 PageC 时,我不再使用相对导航将堆栈推入堆栈,我现在正在导航到这样的根页面:

         await Shell.Current.GoToAsync("//PageC");
        
      3. 在我们导航到 PageC 之前,我们需要清除当前的导航堆栈。我尝试了 PopToRootAsync,但这在导航到 PageC 之前显示了 SearchPage。我发现以下代码有效:

             // FYI - Navigation Stack: //SearchPage/PageA/PageB
        
             var pageB = Shell.Current.Navigation.NavigationStack[2];
             var pageA = Shell.Current.Navigation.NavigationStack[1];
        
             Shell.Current.Navigation.RemovePage(pageB);
             Shell.Current.Navigation.RemovePage(pageA);
        
             // Now navigate to our route page, PageC.
             await Shell.Current.GoToAsync("//PageC");
        

      我将使用一种更优雅的方式来获取页面,而不是对索引进行硬编码,但我认为这是展示正在发生的事情的最简单方法。

      下次我现在导航到 SearchPage 时,我会得到 SearchPage

      【讨论】:

      • 很高兴找到了解决方案!有时间时不要忘记将此标记为答案。然后其他有相同需求的人就会知道。
      • @Craig 是这样吗,如果要清除堆栈,必须在 Shell 视觉层次结构中添加页面?
      • @ThamaraiT 不,要清除堆栈,您必须导航到根目录。在可视层次结构中添加页面只会使该页面成为根页面。
      • 需要提交功能请求,因为官方文档说在Shell视觉层次结构中定义页面时,页面始终位于根目录。 docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/…
      • @ThamaraiT 已经是这样了。仅当您添加页面时(第 2 页到第 1 页...添加不在视觉层次结构中的页面)...当您离开时第 2 页保持原位,并在使用菜单时返回第 1 页。
      【解决方案4】:

      我认为这个功能是故意的。要理解的一件事是,如文档中所述,每个 Tab 都包含单独的导航堆栈,Shell.Current.Navigation 指向当前活动/可见的 Tab 导航堆栈。所以你能做的其实很简单。

      您只需覆盖 Shell.OnNavigating 事件,并且仅当您在不同的路由树之间导航时,才从当前导航堆栈中删除除根页面之外的所有页面。

      比如,从 //route1/page1 到 //route2/page2。

      您可以根据您的用例调整以下代码。

      public partial class AppShell : Xamarin.Forms.Shell
      {
          public AppShell()
          {
              InitializeComponent();
      
              Setup.RegisterRoutes(this);
          }
      
          protected override void OnNavigating(ShellNavigatingEventArgs args)
          {
              base.OnNavigating(args);
      
              if (args.Current != null && args.Target != null && args.Current.Location.OriginalString.StartsWith("//") && args.Target.Location.OriginalString.StartsWith("//")) {
                  var currentRoot = args.Current.Location.OriginalString.TrimStart('/').Split('/').First();
                  var targetRoot = args.Target.Location.OriginalString.TrimStart('/').Split('/').First();
                  
                  // we are navigating between tabs
                  if (!string.Equals(currentRoot, targetRoot, StringComparison.OrdinalIgnoreCase) && Navigation.NavigationStack.Count > 1) {
                      for (var i = Navigation.NavigationStack.Count - 1; i > 0; i--) {
                          Navigation.RemovePage(Navigation.NavigationStack[i]);
                      }
                  }
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-16
        • 1970-01-01
        • 1970-01-01
        • 2018-04-12
        • 2021-07-16
        • 2022-01-25
        相关资源
        最近更新 更多