JamesS
JamesS

Reputation: 2300

Navigation.PushAsync doesn't seem to be showing next page although hitting the constructor

I am creating a multi-page Xamarin application that allows the user to login in and view locations against that user.

I am able to show the login screen, the user can login via calls to a local database however when I try and use Navigation.PushAsync to go to the next page, although hitting the constructor for the next page, nothing seems to happen.

I believe it may have something to do with this section of code here.

Login.xaml.cs

    public Login()
    {
        _Login login = new _Login();
        this.BindingContext = login;
        InitializeComponent();
    }

I've set the Login page as my Main page in App.xaml.cs however in the constructor I set the binding context to a class called _login. This class gets and sets the email and password for the user when they login and calls off to an external solution to access the sql database. (This all works correctly).

On the login button such as this:

Login.xaml

        <Button Command="{Binding SubmitCommand}"
                Text="Login"
                FontAttributes="Bold"
                FontSize="Large"></Button>

Which when clicked calls off to the SubmitCommand function as seen below:

_login.cs

    public async void OnSubmit()
    {
        SignInResponse response = await _clientBl.SignInAsync(Email, Password);

        Login login = new Login();

        if(response.WasSuccessful == true)
        {
            login.LoginSuccessful(response.User);
        }
        else
        {
            // Show error alert
        }
    }

Which, if successful, calls a function in Login.xaml.cs

    public async void LoginSuccessful(ApplicationUser user)
    {
        // Go to home page
        await Navigation.PushAsync(new MainPage
        {
            BindingContext = user
        });
    }

which simply pushes a new page and sets the binding context to that of the user. The code hits the constructor in MainPage.xaml.cs however the page is never loaded up. The MainPage contains a stacklayout with a list view

<StackLayout>
    <ListView ItemsSource="{Binding Locations}"
              ItemSelected="Locations_ItemSelected"
              x:Name="listView">
        <ListView.RowHeight>
            <OnPlatform x:TypeArguments="x:Int32">
                <On Platform="iOS">100</On>
                <On Platform="Android">100</On>
            </OnPlatform>
        </ListView.RowHeight>
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="100"></RowDefinition>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"></ColumnDefinition>
                            <ColumnDefinition Width="*"></ColumnDefinition>
                        </Grid.ColumnDefinitions>
                        <Image Source="{Binding Image}"
                                Aspect="AspectFill" Grid.ColumnSpan="2"></Image>
                        <Label Margin="5" 
                                Text="{Binding Name}"
                                VerticalTextAlignment="Center"
                                HorizontalTextAlignment="Start"
                                Grid.Row="0"
                                Grid.Column="0"
                                TextColor="White"
                                FontSize="25"></Label>
                        <Label Text="{Binding LocationID}"
                               IsVisible="False"></Label>
                    </Grid>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</StackLayout>

which is populated through overriding the OnAppear() function. Could the issue be that I am sending this page an ApplicationUser and it is trying to bind the properties in that page to that class?

I did try and replacing the Navigation.PushAsync with await Navigation.PushAsync(new MainPage()); however it still doesn't show the next page.

Upvotes: 1

Views: 1412

Answers (3)

Sam Tigle
Sam Tigle

Reputation: 403

For my case this happened because I accidentally had pushed the Login page as Modal on the navigation stack. On that (modal) Login Page I had a "register" button which triggered an pushAsync on the Navigation Stack. The Page "didn't show" although i saw its on the navigation stack in debug because the modal was still above it.

The Solution in that case was to simply not push the Login Page as Modal on the Navigation stack.

Upvotes: 0

Jason
Jason

Reputation: 89082

here you are creating a NEW instance of the Login page. You want to use the EXISITNG instance that is already being displayed to the user

Login login = new Login();

if(response.WasSuccessful == true)
{
  login.LoginSuccessful(response.User);

there are a lot of different ways to approach this, but the simplest is probably

var login = (Login)Application.Current.MainPage;

if(response.WasSuccessful == true)
{
  login.LoginSuccessful(response.User);

or if your MainPage is a NavigationPage

var nav = (NavigationPage)Application.Current.MainPage;
var login = (Login)nav.CurrentPage;

Upvotes: 2

Saamer
Saamer

Reputation: 5099

Most likely from the behavior you are describing (and looking at your code), it sounds like it's because the PushAsync is not being run on the UI thread, and this causes the app to load the page on a separate thread. So your app is probably, it's just launching the page on a different thread.

Try to change it to the following:

Device.BeginInvokeOnMainThread(() =>
{
    Navigation.PushAsync(new MainPage
    {
        BindingContext = user
    });
});

Let me know if that makes sense.

Upvotes: 0

Related Questions