In this exercise, we will use .NET MAUI to find the closest monkey to us and also open a map with the Monkeys location.
We can easily check to see if our user is connected to the internet with the built in IConnectivity
of .NET MAUI
-
First, let's get access to the
IConnectivity
found inside of .NET MAUI. Let's injectIConnectivity
into ourMonkeysViewModel
constructor:IConnectivity connectivity; public MonkeysViewModel(MonkeyService monkeyService, IConnectivity connectivity) { Title = "Monkey Finder"; this.monkeyService = monkeyService; this.connectivity = connectivity; }
-
Register the
Connectivity.Current
in ourMauiProgram.cs
. -
Add the following code below the previous builder calls in MauiProgram.cs:
builder.Services.AddSingleton<IConnectivity>(Connectivity.Current); builder.Services.AddSingleton<IGeolocation>(Geolocation.Default); builder.Services.AddSingleton<IMap>(Map.Default);
-
Now, let's check for internet connectivity inside of the
GetMonkeysAsync
method in ViewModel->MonkeysViewModel.cs and display an alert if offline.
Note: Add prior to the if(IsBusy) line.
```csharp
if (connectivity.NetworkAccess != NetworkAccess.Internet)
{
await Shell.Current.DisplayAlert("No connectivity!",
$"Please check internet and try again.", "OK");
return;
}
```
Note: We can't demonstrate this on a Windows VM but using a device or emulator you could test by turning on and off airplane mode.
We can add more functionality to this page using the GPS of the device since each monkey has a latitude and longitude associated with it.
-
First, let's get access to the
IGeolocator
found inside of .NET MAUI. Let's injectIGeolocator
into ourMonkeysViewModel
constructor:IConnectivity connectivity; IGeolocation geolocation; public MonkeysViewModel(MonkeyService monkeyService, IConnectivity connectivity, IGeolocation geolocation) { Title = "Monkey Finder"; this.monkeyService = monkeyService; this.connectivity = connectivity; this.geolocation = geolocation; }
-
In our
MonkeysViewModel.cs
, let's create another method calledGetClosestMonkey
:[RelayCommand] async Task GetClosestMonkey() { }
-
We can then fill it in by using .NET MAUI to query for our location and helpers that find the closest monkey to us:
[RelayCommand] async Task GetClosestMonkey() { if (IsBusy || Monkeys.Count == 0) return; try { // Get cached location, else get real location. var location = await geolocation.GetLastKnownLocationAsync(); if (location == null) { location = await geolocation.GetLocationAsync(new GeolocationRequest { DesiredAccuracy = GeolocationAccuracy.Medium, Timeout = TimeSpan.FromSeconds(30) }); } // Find closest monkey to us var first = Monkeys.OrderBy(m => location.CalculateDistance( new Location(m.Latitude, m.Longitude), DistanceUnits.Miles)) .FirstOrDefault(); await Shell.Current.DisplayAlert("", first.Name + " " + first.Location, "OK"); } catch (Exception ex) { Debug.WriteLine($"Unable to query location: {ex.Message}"); await Shell.Current.DisplayAlert("Error!", ex.Message, "OK"); } }
-
Back in our
MainPage.xaml
we can add anotherButton
that will call this new method:Add the following XAML under the Search button.
<Button Text="Find Closest" Command="{Binding GetClosestMonkeyCommand}" IsEnabled="{Binding IsNotBusy}" Grid.Row="1" Grid.Column="1" Style="{StaticResource ButtonOutline}" Margin="8"/>
Re-run the app to see geolocation in action after you load monkeys!
.NET MAUI provides over 60 platform features from a single API and opening the default map application is built in!
-
Inject
IMap
into ourMonkeyDetailsViewModel
:IMap map; public MonkeyDetailsViewModel(IMap map) { this.map = map; }
-
Open the
MonkeyDetailsViewModel.cs
file and add a method calledOpenMap
that calls into theMap
API passing it the monkey's location:[RelayCommand] async Task OpenMap() { try { await map.OpenAsync(Monkey.Latitude, Monkey.Longitude, new MapLaunchOptions { Name = Monkey.Name, NavigationMode = NavigationMode.None }); } catch (Exception ex) { Debug.WriteLine($"Unable to launch maps: {ex.Message}"); await Shell.Current.DisplayAlert("Error, no Maps app!", ex.Message, "OK"); } }
Above the monkey's name (the label bound with Binding Monkey.Name), let's add a button that calls the OpenMapCommand
.
<Button Text="Show on Map"
Command="{Binding OpenMapCommand}"
HorizontalOptions="Center"
WidthRequest="200"
Margin="8"
Style="{StaticResource ButtonOutline}"/>
Run the application, navigate to a monkey, and then press Show on Map to launch the map app on the specific platform.
In addition to accessing cross-platform device APIs, .NET MAUI also includes platform specific integrations. If you run the Monkey Finder app on an iOS device with a notch, you may have noticed that the buttons on the bottom overlap the bar on the bottom of the device. iOS has the concept of Safe Areas and you must progmatically set this. However, thanks to platform specifics, you can set them directly in the XAML.
-
Open
MainPage.xaml
and add a new namespace for iOS specifics:xmlns:ios="clr-namespace:Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;assembly=Microsoft.Maui.Controls"
-
On the
ContentPage
node, you can now set the following property:ios:Page.UseSafeArea="True"
Re-run the application on an iOS simulator or device and notice the buttons have automatically been shifted up.
Let's move forward to the next module and learn about the Collection View in the next exercise.