问题描述
我的Xamarin Forms Shell应用出现问题。我不确定这是错误还是预期的行为,有人可以向我指出正确的方向。
我在Visual Shell层次结构中有一个包含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)
Shell.Current.GoToAsync("PageA");
因为PageA不在视觉层次结构中,所以这给了我这样的导航堆栈:
"//searchpage/PageA"
使用相同的相对导航方法,我先导航到PageB,然后导航到PageC,所以我的导航堆栈如下:
"//searchpage/PageA/PageB/PageC"
在PageC中,我使用弹出菜单导航至“历史记录”,历史记录页面可以正常打开。
现在在历史记录页面上,我再次使用弹出菜单,然后单击“搜索”标签
但是我并没有像预期的那样进入搜索页面,而是回到了PageC(回到了我以前的导航堆栈)。
如果我再次使用弹出菜单并单击“搜索”选项卡,则在此页面(PageC)中,它会正确导航到“搜索”页面。
当从弹出菜单中选择“搜索”选项卡时,该如何工作以及如何停止导航到PageC?
谢谢
(ps-我目前正在使用Xamarin Forms 4.7)
解决方法
我将在5分钟后提出此功能请求,但我已找到解决该问题的方法。
-
我将最后一页(PageC)设置为根页面,并将其从我的路线脚本中删除。为此,我将以下内容添加到AppShell.Xaml中:
<ShellItem Route="PageC"> <ShellContent ContentTemplate="{DataTemplate views:PageC}" /> </ShellItem> and removing this code: Routing.RegisterRoute("PageC",typeof(PageC));
-
现在导航到PageC时,我不再使用相对导航推入堆栈,现在我导航到这样的根页面:
await Shell.Current.GoToAsync("//PageC");
-
在导航到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
,我认为这个功能是故意的。需要理解的一件事是,如文档中所述,每个 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]);
}
}
}
}
}