Switch App Shell Tab programmatically to current page on tab, not with GotoAsync – Xamarin Forms/Maui App Shell

huangapple go评论68阅读模式
英文:

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(&quot;//NewPage1&quot;);

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

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
&lt;Shell
    x:Class=&quot;ShellNavTest.AppShell&quot;
.. xmlns removed due to filters
    xmlns:local=&quot;clr-namespace:ShellNavTest&quot;
    Shell.FlyoutBehavior=&quot;Disabled&quot;&gt;
&lt;!--
    &lt;ShellContent
        Title=&quot;Home&quot;
        ContentTemplate=&quot;{DataTemplate local:MainPage}&quot;
        Route=&quot;MainPage&quot; /&gt; --&gt;
    &lt;TabBar&gt;
        &lt;ShellContent Title=&quot;Page1&quot; Route=&quot;NewPage1&quot; ContentTemplate=&quot;{DataTemplate local:NewPage1}&quot; /&gt;
        &lt;ShellContent Title=&quot;Page2&quot; Route=&quot;NewPage2&quot; ContentTemplate=&quot;{DataTemplate local:NewPage2}&quot; /&gt;
        &lt;ShellContent Title=&quot;Page3&quot; Route=&quot;NewPage3&quot; ContentTemplate=&quot;{DataTemplate local:NewPage3}&quot; /&gt;
        &lt;ShellContent Title=&quot;Page4&quot; Route=&quot;NewPage4&quot; ContentTemplate=&quot;{DataTemplate local:NewPage4}&quot; /&gt;
    &lt;/TabBar&gt;
&lt;/Shell&gt;

NewPage1.xaml

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;ContentPage 
.. xmlns removed due to filters
             x:Class=&quot;ShellNavTest.NewPage1&quot;
             Title=&quot;NewPage1&quot;
             Shell.TabBarIsVisible=&quot;True&quot; &gt;
    &lt;VerticalStackLayout&gt;
        &lt;Label 
            Text=&quot;Page 1&quot;
            VerticalOptions=&quot;Center&quot; 
            HorizontalOptions=&quot;Center&quot; /&gt;
        &lt;Button x:Name=&quot;btnCreateChild&quot; Text=&quot;Create Child&quot; Clicked=&quot;btnCreateChild_Clicked&quot; Margin=&quot;20&quot; /&gt;
    &lt;/VerticalStackLayout&gt;
&lt;/ContentPage&gt;

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

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;ContentPage 
.. xmlns removed due to filters
             x:Class=&quot;ShellNavTest.ChildPage&quot;
             Title=&quot;ChildPage&quot;
             Shell.TabBarIsVisible=&quot;True&quot; &gt;
    &lt;VerticalStackLayout BackgroundColor=&quot;Cyan&quot;&gt;
        &lt;Label 
            Text=&quot;this is a child page on navigation stack but not in routes&quot;
            VerticalOptions=&quot;Center&quot; 
            HorizontalOptions=&quot;Center&quot; /&gt;
    &lt;/VerticalStackLayout&gt;
&lt;/ContentPage&gt;

NewPage2.xaml

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;ContentPage 
.. xmlns removed due to filters
             x:Class=&quot;ShellNavTest.NewPage2&quot;
             Title=&quot;NewPage2&quot;
             Shell.TabBarIsVisible=&quot;True&quot; &gt;
    &lt;VerticalStackLayout&gt;
        &lt;Label 
            Text=&quot;Page 2&quot;
            VerticalOptions=&quot;Center&quot; 
            HorizontalOptions=&quot;Center&quot; /&gt;
        &lt;Button x:Name=&quot;btnGotoPage1&quot; Text=&quot;Goto Page 1&quot; Clicked=&quot;btnGotoPage1_Clicked&quot; Margin=&quot;20&quot; /&gt;
    &lt;/VerticalStackLayout&gt;
&lt;/ContentPage&gt;

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(&quot;//NewPage1&quot;);
    }

}

答案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

    &lt;TabBar x:Name=&quot;shelltabbar&quot;&gt;
        &lt;Tab x:Name=&quot;shelltab_0&quot; Title=&quot;Page1&quot;&gt;
        &lt;ShellContent Title=&quot;Page1&quot; Route=&quot;NewPage1&quot; ContentTemplate=&quot;{DataTemplate local:NewPage1}&quot; /&gt;
        &lt;/Tab&gt;
        &lt;Tab x:Name=&quot;shelltab_1&quot; Title=&quot;Page2&quot;&gt;
            &lt;ShellContent Title=&quot;Page2&quot; Route=&quot;NewPage2&quot; ContentTemplate=&quot;{DataTemplate local:NewPage2}&quot; /&gt;
        &lt;/Tab&gt;
        &lt;Tab x:Name=&quot;shelltab_2&quot; Title=&quot;Page3&quot;&gt;
            &lt;ShellContent Title=&quot;Page3&quot; Route=&quot;NewPage3&quot; ContentTemplate=&quot;{DataTemplate local:NewPage3}&quot; /&gt;
        &lt;/Tab&gt;
        &lt;Tab x:Name=&quot;shelltab_3&quot; Title=&quot;Page4&quot;&gt;
            &lt;ShellContent Title=&quot;Page4&quot; Route=&quot;NewPage4&quot; ContentTemplate=&quot;{DataTemplate local:NewPage4}&quot; /&gt;
        &lt;/Tab&gt;
    &lt;/TabBar&gt;

AppShell.xaml.cs

namespace ShellNavTest;

public partial class AppShell : Shell
{
	public AppShell()
	{
		InitializeComponent();
	}
    public void SwitchtoTab(int tabIndex)
    {
        Device.BeginInvokeOnMainThread(() =&gt;
        {
            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);
    }

huangapple
  • 本文由 发表于 2023年2月24日 06:59:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/75551165.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定