How to switch tabs programmatically, as if the user had clicked the tabbar's tab button instead of using GoToAsync()
I have a Maui app (but the same in Xamarin Forms) with an App Shell <TabBar with 4 pages Each TabPage works independently, but I push new pages onto (Tab 1's) stack via
Shell.Current.Navigation.PushAsync(new ChildPage() );
(Further use case: The stack is dynamic, in that "ChildPage1" is not always in 1 place, and may be used several times in the stack, therefore I cannot use an absolute route path)
If I then use the navigation tab buttons, I can switch to a new tab and back, and it retains each Tab's stack (e.g. switching from Tab 2 to Tab 1 below would show "Child Page 2" [Tab 1] NewPage 1 Child Page 1 Child Page 2
[Tab 2] NewPage 2
[Tab 3] etc..
I need to be able to do this programmatically instead of clicking the tab button The only Navigation I have seen so far is
await Shell.Current.GoToAsync("//NewPage1");
which isn't what I want
Is there a way to do this? Is this even exposed, or do I have to manually track the Navigated() event for instance and GoToAsync the full remembered path?
sample app portions AppShell.xaml relevant portions
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="ShellNavTest.AppShell"
.. xmlns removed due to filters
xmlns:local="clr-namespace:ShellNavTest"
Shell.FlyoutBehavior="Disabled">
<!--
<ShellContent
Title="Home"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" /> -->
<TabBar>
<ShellContent Title="Page1" Route="NewPage1" ContentTemplate="{DataTemplate local:NewPage1}" />
<ShellContent Title="Page2" Route="NewPage2" ContentTemplate="{DataTemplate local:NewPage2}" />
<ShellContent Title="Page3" Route="NewPage3" ContentTemplate="{DataTemplate local:NewPage3}" />
<ShellContent Title="Page4" Route="NewPage4" ContentTemplate="{DataTemplate local:NewPage4}" />
</TabBar>
</Shell>
NewPage1.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
.. xmlns removed due to filters
x:Class="ShellNavTest.NewPage1"
Title="NewPage1"
Shell.TabBarIsVisible="True" >
<VerticalStackLayout>
<Label
Text="Page 1"
VerticalOptions="Center"
HorizontalOptions="Center" />
<Button x:Name="btnCreateChild" Text="Create Child" Clicked="btnCreateChild_Clicked" Margin="20" />
</VerticalStackLayout>
</ContentPage>
NewPage1.xaml.cs
namespace ShellNavTest;
public partial class NewPage1 : ContentPage
{
public NewPage1()
{
InitializeComponent();
}
private void btnCreateChild_Clicked(object sender, EventArgs e)
{
Shell.Current.Navigation.PushAsync(new ChildPage() );
}
}
ChildPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
.. xmlns removed due to filters
x:Class="ShellNavTest.ChildPage"
Title="ChildPage"
Shell.TabBarIsVisible="True" >
<VerticalStackLayout BackgroundColor="Cyan">
<Label
Text="this is a child page on navigation stack but not in routes"
VerticalOptions="Center"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentPage>
NewPage2.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
.. xmlns removed due to filters
x:Class="ShellNavTest.NewPage2"
Title="NewPage2"
Shell.TabBarIsVisible="True" >
<VerticalStackLayout>
<Label
Text="Page 2"
VerticalOptions="Center"
HorizontalOptions="Center" />
<Button x:Name="btnGotoPage1" Text="Goto Page 1" Clicked="btnGotoPage1_Clicked" Margin="20" />
</VerticalStackLayout>
</ContentPage>
NewPage2.xaml.cs
namespace ShellNavTest;
public partial class NewPage2 : ContentPage
{
public NewPage2()
{
InitializeComponent();
}
private async void btnGotoPage1_Clicked(object sender, EventArgs e)
{
await Shell.Current.GoToAsync("//NewPage1");
}
}
I solved this by x:name -ing the TabBar and encompassing the ShellContent in named tabs, then setting the tabbar's CurrentItem specifically
AppShell.xaml
<TabBar x:Name="shelltabbar">
<Tab x:Name="shelltab_0" Title="Page1">
<ShellContent Title="Page1" Route="NewPage1" ContentTemplate="{DataTemplate local:NewPage1}" />
</Tab>
<Tab x:Name="shelltab_1" Title="Page2">
<ShellContent Title="Page2" Route="NewPage2" ContentTemplate="{DataTemplate local:NewPage2}" />
</Tab>
<Tab x:Name="shelltab_2" Title="Page3">
<ShellContent Title="Page3" Route="NewPage3" ContentTemplate="{DataTemplate local:NewPage3}" />
</Tab>
<Tab x:Name="shelltab_3" Title="Page4">
<ShellContent Title="Page4" Route="NewPage4" ContentTemplate="{DataTemplate local:NewPage4}" />
</Tab>
</TabBar>
AppShell.xaml.cs
namespace ShellNavTest;
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
}
public void SwitchtoTab(int tabIndex)
{
Device.BeginInvokeOnMainThread(() =>
{
switch (tabIndex)
{
case 0: shelltabbar.CurrentItem = shelltab_0; break;
case 1: shelltabbar.CurrentItem = shelltab_1; break;
case 2: shelltabbar.CurrentItem = shelltab_2; break;
case 3: shelltabbar.CurrentItem = shelltab_3; break;
};
});
}
}
ChildPage.xaml.cs
private void btnSwitchToTab1_Clicked(object sender, EventArgs e)
{
((AppShell)App.Current.MainPage).SwitchtoTab(0);
}