Search code examples
c#iosnavigationmaui

Using NavigationPage in Maui causes app to crash immediately


I'm developing an Maui iOS app and I got a fully functional app that works with no issue. The problem I'm having is that there is no back button like there is in Android which allows the user to return to the previous page nor is there a NavigationBar like what is generated by default in Xamarin.

As I understand it, the Swipe Back capability is disabled when one doesn't use a NavigationBar or NavigationPage, so I'm trying to add a NavigationBar or NavigationPage so the user has that back arrow or button to return to the previous screen. I have been using the example here to add the code I need for the bar to appear. But as soon as I add this code to my App.xaml.cs code files

MainPage = new NavigationPage(new Logon());

the app immediately crashes when I run it on my test device. The app breaks on the line ' UIApplication.Main(args, null, typeof(AppDelegate)); ' in the program.cs code file in the iOS folder with the error System.NullReferenceException Message=Object reference not set to an instance of an object.. That code is:

public class Program
{
    // This is the main entry point of the application.
    static void Main(string[] args)
    {
        // if you want to use a different Application Delegate class from "AppDelegate"
        // you can specify it here.
        UIApplication.Main(args, null, typeof(AppDelegate));
    }
}

I've reported the issue to Microsoft here for those who want to look at all my research thus far. There were several issues I was running into when I was trying different things, all but this one cleared up after updating my mac and test iPhone to the latest OS.

********** EDIT *******************

This is the Logon code:

public partial class Logon : ContentPage
{
    public Logon()
    {
        InitializeComponent();
    }
    User MyUser = new User();
    CompanyInformation MyCompany = new CompanyInformation();
    bool error = false;
    private async void OnCounterClicked(object sender, EventArgs e)
    {
        string username = TheUsername.Text;
        string password = ThePassword.Text;
        if (username != null)
        {
            if (password != null)
            {
                activityIndicator.IsVisible = true;
#if ANDROID
                await Task.Run(() => SignOn());
#elif IOS
                iOSSignon();
#endif
            }
            else
            {
                await DisplayAlert("ERROR", "Enter your password.", "OK");
            }
        }
        else
        {
            await DisplayAlert("ERROR", "Enter your username.", "OK");
        }

    }
    public void iOSSignon()
    {
        string result = "";


        MyUser.Username = TheUsername.Text.Trim();
        MyUser.Password = ThePassword.Text.Trim();
        try
        {

            bool isOnline = Utils.IsConnectedToTheInternet();

            if (isOnline)
            {
                MyServiceSoapClient myService = new MyServiceSoapClient(MyServiceSoapClient.EndpointConfiguration.MyServiceSoap);
                try
                {
                    result = myService.Logon(MyUser.Username, MyUser.Password);
                }
                catch (Exception ex)
                {
                    Utils.LogError("App:MyApp/Logon.xaml.cs/SignOn - An error occured in SignOn function, the error is: " + ex.Message + System.Environment.NewLine + Utils.GetExceptionInfo(ex));
                    DisplayAlert("ERROR", "There was an error in the logon process. The error was reported to technical support, please try again later of contact technical support at Support@MyCompany.com.", "OK");
                }
            }
            else
            {
                DisplayAlert("Information", "There is no internet connection or cell phone connection.  Connect to a wifi network or a cellular network.", "OK");
            }
        }
        catch (Exception ex)
        {
            Utils.LogError("App:MyApp/Logon.xaml.cs - An error occured in the SignOn function, the error is: " + ex.Message + System.Environment.NewLine + Utils.GetExceptionInfo(ex));
            DisplayAlert("ERROR", "An error occured in the logon process.  The error was reported to technical support, please try again later or contact technical support at Support@MyCompany.com.", "OK");
        }

        if (result == "CONNECTED")
        {
            Menu MyMenu = new Menu();
            MyMenu.MyUser = MyUser;
            Navigation.PushModalAsync(MyMenu);
        }
        else if (result == "DISABLED")
        {
            DisplayAlert("Information", "Your account has been disabled, contact your supervisor for more information.", "OK");
        }
        else
        {
            try
            {
                error = true;
                DisplayAlert("Information", "Invalid username or password.", "OK");
            }
            catch (Exception ex)
            {
                Utils.LogError("App:MyApp/Logon.xaml.cs/SignOn() - An error occured in the Logon.xaml.cs SignOn function result = connected, the error is: " + ex.Message + System.Environment.NewLine + Utils.GetExceptionInfo(ex));
                DisplayAlert("ERROR", "An error occurred during the logon process.  The error has been reported to technical support, please try again or contact technical support at Support@MyCompany.com", "OK");
            }
        }
        ;
        try
        {
            if (error)
            {
                Utils.LogError("App:MyApp/Logon.xaml.cs/SignOn() (2) - An error occured in the Logon.xaml.cs SignOn function result = connected, the error is: ");
            }
        }
        catch (Exception ex)
        {
            Utils.LogError("App:MyApp/Logon.xaml.cs/SignOn() (2) - An error occured in Logon.xaml.cs Signin function (second block), the error is: " + ex.Message + System.Environment.NewLine + Utils.GetExceptionInfo(ex));
            DisplayAlert("ERROR", "An error occurred during the logon process (2).  The error has been reported to technical support, please try again or contact technical support at Support@MyCompany.com", "OK");
        }
    }
    private async Task SignOn()
    {
        string result = "";


        MyUser.Username = TheUsername.Text.Trim();
        MyUser.Password = ThePassword.Text.Trim();
        try
        {

            bool isOnline = Utils.IsConnectedToTheInternet();

            if (isOnline)
            {
                MyServiceSoapClient myService = new MyServiceSoapClient(MyServiceSoapClient.EndpointConfiguration.MyServiceSoap);
                try
                {
                    result = myService.Logon(MyUser.Username, MyUser.Password);
                }
                catch (Exception ex)
                {
                    Utils.LogError("App:MyApp/Logon.xaml.cs/SignOn - An error occured in SignOn function, the error is: " + ex.Message + System.Environment.NewLine + Utils.GetExceptionInfo(ex));
                    await DisplayAlert("ERROR", "There was an error in the logon process. The error was reported to technical support, please try again later of contact technical support at Support@MyCompany.com.", "OK");
                }
            }
            else
            {
                await DisplayAlert("Information", "There is no internet connection or cell phone connection.  Connect to a wifi network or cellular network.", "OK");
            }
            ;
        }
        catch (Exception ex)
        {
            Utils.LogError("App:MyApp/Logon.xaml.cs - An error occured in the SignOn function, the error is: " + ex.Message + System.Environment.NewLine + Utils.GetExceptionInfo(ex));
            await DisplayAlert("ERROR", "An error occured in the logon process.  The error was reported to technical support, please try again later or contact technical support at Support@MyCompany.com.", "OK");
        }
        ;

        if (result == "CONNECTED")
        {
                Menu MyMenu = new Menu();
                MyMenu.MyUser = MyUser;
                await Navigation.PushModalAsync(MyMenu);
        }
        else if (result == "DISABLED")
        {
            await DisplayAlert("Information", "Your account has been disabled, contact your subervisor for more information.", "OK");
        }
        else
        {
            try
            {
                error = true;
                await DisplayAlert("Information", "Invalid username or password.", "OK");
            }
            catch (Exception ex)
            {
                Utils.LogError("App:MyApp/Logon.xaml.cs/SignOn() - An error occured in the Logon.xaml.cs SignOn function result = connected, the error is: " + ex.Message + System.Environment.NewLine + Utils.GetExceptionInfo(ex));
                await DisplayAlert("ERROR", "An error occurred during the logon process.  The error has been reported to technical support, please try again or contact technical support at Support@MyCompany.com", "OK");
            }
        }
        ;
        try
        {
            if (error)
            {
                Utils.LogError("App:MyApp/Logon.xaml.cs/SignOn() (2) - An error occured in the Logon.xaml.cs SignOn function result = connected, the error is: ");
            }
        }
        catch (Exception ex)
        {
            Utils.LogError("App:MyApp/Logone.xaml.cs/SignOn() (2) - An error occured in Logon.xaml.cs Signin function (second block), the error is: " + ex.Message + System.Environment.NewLine + Utils.GetExceptionInfo(ex));
            await DisplayAlert("ERROR", "An error occurred during the logon process (2).  The error has been reported to technical support, please try again or contact technical support at Support@MyCompany.com", "OK");
        }
    }
}

This is the Logon xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.Logon"
             x:DataType="Line"
             Title="Logon">
    <ScrollView>
        <VerticalStackLayout
            Padding="5,0"
            Spacing="10">
            <Image
                Source="banner2.jpg"
                HeightRequest="75"
                Aspect="AspectFit"
                SemanticProperties.Description="My Company" />

            <Line Stroke="Black" X2="{Binding Width, Source={RelativeSource Self}}" HorizontalOptions="Fill" StrokeThickness="2" />

            <ActivityIndicator x:Name="activityIndicator"
                       IsVisible="false"
                       IsRunning="True"
                       VerticalOptions="Center" HorizontalOptions="Center"
                       WidthRequest="100" HeightRequest="100"/>
            <Label
                Text="Log On"
                Style="{StaticResource Headline}"
                SemanticProperties.HeadingLevel="Level1" />

            <Label
                Text="Username"
                Style="{StaticResource SubHeadline}"
                SemanticProperties.HeadingLevel="Level2"
                SemanticProperties.Description="Enter your username." />

            <Entry x:Name="TheUsername"
                Placeholder="Enter Username"/>

            <Label
                Text="Password"
                Style="{StaticResource SubHeadline}"
                SemanticProperties.HeadingLevel="Level2"
                SemanticProperties.Description="Enter your password." />

            <Entry x:Name="ThePassword"
                Placeholder="Enter Password"
                IsPassword="true" />

            <Button
                x:Name="CounterBtn"
                Text="Submit" 
                SemanticProperties.Hint="Log on"
                Clicked="OnCounterClicked"
                HorizontalOptions="Fill" />

        </VerticalStackLayout>
    </ScrollView>
</ContentPage>

Solution

  • I resolved the issue with the following code in App.xaml.cs:

    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();
        }
        protected override Window CreateWindow(IActivationState? activationState)
        {
            Window window = new Window();
    #if ANDROID
    
            window = new Window(new AppShell());
    #elif IOS
            NavigationPage navigation = new NavigationPage(new Logon());
            //navigation.BarBackground = Colors.Blue;
            //navigation.BarTextColor = Colors.White;
            //.Ivisible = true;
            window = new Window(navigation);
    #endif
            return window;
        }
    }
    

    It seems that if I want the NavigationBar on my ContentPages I would need to wrap each ContentPage with a NavigationPage as so, new Navigation(new contentpage());, and then add the controls I would want. I didn't want to do that so I commented out the code that makes the bar appear, but that knowledge will certainly come in handy for future apps. For this particular app I use an Exit button to execute PopModalAysnc() which removes the current page from the stack. That function isn't available apparently without first "initiating" a navigation page. Everytime I tried to use PopModalAysnc() before I got the error it wasn't supported. With the Android version of the app, I stuck with the default navigation (whatever that is) because Android has a default back button that works just fine and only use the NavigationPage with the iOS version. I already have the Android version on the play store and didn't want to make any changes to code that was working.