英文:
Switch App Shell Tab programmatically to current page on tab, not with GotoAsync - Xamarin Forms/Maui App Shell
问题
如何在程序中切换选项卡,就好像用户点击了选项卡栏的选项卡按钮而不是使用GoToAsync()方法:
我有一个Maui应用程序(但在Xamarin Forms中也一样),其中有一个带有4个页面的App Shell的选项卡栏。每个TabPage都可以独立工作,但我通过以下方式将新页面推送到(Tab 1的)堆栈中:
Shell.Current.Navigation.PushAsync(new ChildPage());
(更多用例:堆栈是动态的,也就是说“ChildPage1”并不总是在同一个位置,可能在堆栈中使用多次,因此我无法使用绝对路径路由)
然后,如果我使用导航选项卡按钮,我可以切换到新的选项卡并返回,它会保留每个选项卡的堆栈(例如,从下面的Tab 2切换到Tab 1会显示“Child Page 2”):
[选项卡 1]
新页面 1
子页面 1
子页面 2
[选项卡 2]
新页面 2
[选项卡 3] 等等..
我需要能够以编程方式执行此操作,而不是点击选项卡按钮。到目前为止,我看到的唯一导航方法是:
await Shell.Current.GoToAsync("//NewPage1");
这不是我想要的。有办法实现这个吗?这甚至是公开的吗,还是我必须手动跟踪Navigated()事件并使用GoToAsync来实现完整的记忆路径?
示例应用程序部分:
AppShell.xaml相关部分:
<!-- 省略了命名空间部分 -->
<Shell
x:Class="ShellNavTest.AppShell"
Shell.FlyoutBehavior="Disabled">
<TabBar>
<ShellContent Title="页面1" Route="NewPage1" ContentTemplate="{DataTemplate local:NewPage1}" />
<ShellContent Title="页面2" Route="NewPage2" ContentTemplate="{DataTemplate local:NewPage2}" />
<ShellContent Title="页面3" Route="NewPage3" ContentTemplate="{DataTemplate local:NewPage3}" />
<ShellContent Title="页面4" Route="NewPage4" ContentTemplate="{DataTemplate local:NewPage4}" />
</TabBar>
</Shell>
NewPage1.xaml:
<!-- 省略了命名空间部分 -->
<ContentPage
x:Class="ShellNavTest.NewPage1"
Title="新页面1"
Shell.TabBarIsVisible="True">
<!-- 省略了内容部分 -->
</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:
<!-- 省略了命名空间部分 -->
<ContentPage
x:Class="ShellNavTest.ChildPage"
Title="ChildPage"
Shell.TabBarIsVisible="True">
<!-- 省略了内容部分 -->
</ContentPage>
NewPage2.xaml:
<!-- 省略了命名空间部分 -->
<ContentPage
x:Class="ShellNavTest.NewPage2"
Title="新页面2"
Shell.TabBarIsVisible="True">
<!-- 省略了内容部分 -->
</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");
}
}
英文:
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");
}
}
答案1
得分: 1
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
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
{
((AppShell)App.Current.MainPage).SwitchtoTab(0);
}
英文:
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);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论