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>
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 ContentPage
s 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.