0

I'm working on a Xamarin.Forms application that includes an onboarding feature. The onboarding page is shown when certain conditions are met, but I'm facing an issue where the OnboardingPage quickly navigates back to the previous page DashboardPage before allowing the user to interact with it.

Here's the current navigation flow:

The application checks if the user is logged in. If logged in, it navigates to the dashboard page. In the dashboard page constructor, it checks if the onboarding should be shown. If these conditions are met, it navigates to the onboarding page using Shell.Current.Navigation.PushModalAsync(). In the onboarding page, there is a button that dismisses the modal page using Navigation.PopModalAsync(). The issue is that after the OnboardingPage is shown, it quickly navigates back to the dashboard page without allowing the user to interact with the onboarding content. The second navigation to the DashboardPage seems to have an animation and lacks a navigation bar, which indicates that it was pushed(or popped?) as a modal page.

I would like to ensure that the user stays on the OnboardingPage until it is completed. How can I modify the navigation flow and handle the conditions properly to prevent the immediate return to the dashboard page? The code snippets are below:

  1. EntryShell.xaml.cs:
public partial class EntryShell : Xamarin.Forms.Shell
{
    public EntryShell()
    {
        InitializeComponent();
        Routing.RegisterRoute("Main1Page", typeof(Main1Page));
        Routing.RegisterRoute("Onboarding", typeof(OnboardingPage));
        Routing.RegisterRoute("LoginPage", typeof(LoginPage));
        Routing.RegisterRoute("RegistrationPage", typeof(RegistrationPage));
        Routing.RegisterRoute("DashboardPage", typeof(DashboardPage));
    }
}

The EntryShell class registers the routes for the various pages using the Routing.RegisterRoute method. This code seems correct and should enable navigation to the registered pages based on their specified routes.

  1. App.xaml.cs:
public partial class App : Application
{
    Page main1Page, dashboardPage;
    BaseViewModel so = new BaseViewModel();

    public App ()
    {
        InitializeComponent();
        MainPage = new EntryShell();

        if (so.IsLogged)
        {
            Current.ModalPopping += Current_ModalPopping;
            dashboardPage = new DashboardPage();
            Shell.Current.Navigation.PushModalAsync(dashboardPage);
        }
    }

    private void Current_ModalPopping(object sender, ModalPoppingEventArgs e)
    {
        if (e.Modal == main1Page)
        {
            main1Page = null;
            Current.ModalPopping -= Current_ModalPopping;
        }
        else if (e.Modal == dashboardPage)
        {
            dashboardPage = null;
            Current.ModalPopping -= Current_ModalPopping;
        }
    }
}

The App class initializes the application. If the IsLogged property of the BaseViewModel instance (so) is true, it sets up the dashboardPage instance and pushes it as a modal page using Shell.Current.Navigation.PushModalAsync(). This code seems fine and should navigate to the dashboard page if the user is logged in.

  1. DashboardPage.xaml.cs:
public partial class DashboardPage : ContentPage
{
    Page onboardingPage = new OnboardingPage();

    public DashboardPage()
    {
        InitializeComponent();
        Debug.WriteLine("Dashboard Constructor Called!");

        if (ShouldShowOnboarding() == true)
        {
            Navi2Onboard();
        }
    }

 private bool ShouldShowOnboarding()
        {

            return true;
            //return VersionTracking.IsFirstLaunchEver;

        }

    private async void Navi2Onboard()
    {
        await Shell.Current.Navigation.PushModalAsync(onboardingPage);
    }
}

The DashboardPage class represents the dashboard page. In the constructor, it checks if the onboarding should be shown by calling the ShouldShowOnboarding() method. If it returns true, it navigates to the onboarding page using Shell.Current.Navigation.PushModalAsync(). This code seems correct.

  1. OnboardingPage.xaml.cs:
public partial class OnboardingPage : ContentPage
{
    public OnboardingPage ()
    {
        InitializeComponent ();
        Debug.WriteLine("Onboard Constructor Called!");
    }

    private async void Button_Clicked(System.Object sender, System.EventArgs e)
    {
        await FadeBox.FadeTo(1, 1000);
        await Navigation.PopModalAsync(false);
    }
}

The OnboardingPage class represents the onboarding page. It contains a button click event handler that fades in a box and dismisses the modal page by calling Navigation.PopModalAsync(). This code appears correct.

  1. Main1Page.xaml.cs:
public partial class Main1Page : ContentPage
{
    BaseViewModel

 x = new BaseViewModel();

    public Main1Page()
    {
        InitializeComponent();
        Debug.WriteLine("Point 1");
    }

    private async void SignUpClicked(System.Object sender, System.EventArgs e)
    {
        await Shell.Current.Navigation.PushAsync(new RegistrationPage());
    }

    private async void LoginClicked(System.Object sender, System.EventArgs e)
    {
        await Shell.Current.Navigation.PushAsync(new LoginPage());
    }

    private async void TapGestureRecognizer_Tapped(System.Object sender, System.EventArgs e)
    {
        await Shell.Current.Navigation.PushModalAsync(new DashboardPage());
    }

    private async void GoToWebsite(System.Object sender, System.EventArgs e)
    {
        await Shell.Current.Navigation.PushAsync(new Webview());
    }
}

The Main1Page class represents a page in your application. It contains event handlers for various button clicks that navigate to different pages using Shell.Current.Navigation.PushAsync() or Shell.Current.Navigation.PushModalAsync(). The code seems fine, assuming the necessary pages (RegistrationPage, LoginPage, DashboardPage, and Webview) are defined correctly.

<EntryShell xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            xmlns:local="clr-namespace:YourNamespace"
            x:Class="YourNamespace.EntryShell">
    <TabBar>
        <ShellContent Route="Main1Page" Shell.FlyoutBehavior="Disabled" NavigationPage.HasNavigationBar="False" ContentTemplate="{DataTemplate local:Main1Page}" />
    </TabBar>

    <TabBar >
        <ShellContent Route="DashboardPage" Shell.FlyoutBehavior="Disabled" ContentTemplate="{DataTemplate local:DashboardPage}"/>
    </TabBar>

    <TabBar>
        <ShellContent Route="Onboarding" Shell.FlyoutBehavior="Disabled" ContentTemplate="{DataTemplate local:OnboardingPage}"/>
    </TabBar>

    <TabBar>
        <ShellContent Route="LoginPage" Shell.FlyoutBehavior="Disabled" ContentTemplate="{DataTemplate local:LoginPage}" />
    </TabBar>

    <TabBar>
        <ShellContent Route="RegistrationPage" Shell.FlyoutBehavior="Disabled" ContentTemplate="{DataTemplate local:RegistrationPage}" />
    </TabBar>
</EntryShell>

The code snippet represents the EntryShell.xaml file, which defines the structure of my Shell-based application. It includes multiple TabBar sections, each containing a ShellContent element specifying the routes and content templates for the associated pages. This is provided for more clarity.

Based on the provided code snippets, the navigation logic appears to be correct. Any insights or suggestions on resolving this navigation issue would be greatly appreciated. Thank you in advance for your help!

Calvin Carter
  • 59
  • 1
  • 7
  • Recommendations: 1) Don’t navigate in constructors. 2) SIMPLIFY to the minimal code that shows the symptom. Don’t show - and don’t describe - two different ways to cause a symptom. Pick one, and remove all code not relevant to that case. Then test that simplified code yourself. – ToolmakerSteve Jun 22 '23 at 23:16

1 Answers1

0

I switched every instance of Shell.Current.Navigation.PushAsync() with Shell.Current.GoToAsync() and kept the onboarding the same Shell.Current.Navigation.PushModalAsync() the same:

from this -->await Shell.Current.Navigation.PushModalAsync(new DashboardPage());

to this -->await Shell.Current.GoToAsync("//DashboardPage");

with DashboardPage being the route registered in the EntryShell.xaml file. Doing this, the onboarding page appears as it should. It has to be something to do with Shell.Current.Navigation that makes it act weird.

Calvin Carter
  • 59
  • 1
  • 7
  • Excellent! You can check [Accept Your Own Answers](https://stackoverflow.blog/2009/01/06/accept-your-own-answers/) as it's helpful to others facing the same problem. – Alexandar May - MSFT Jun 26 '23 at 03:56