The .NET MAUI Maps library comes with a powerful feature, tile layer support, which renders map tiles from various web maps tile services such as Bing Maps, OpenStreetMap, Google Maps, and TomTom. The tile layer feature enables developers to create highly customized maps with different base layers and overlays, providing users rich and interactive mapping experiences.
Whether for tracking locations, analyzing data, or visualizing geographic information, the tile layer feature of the .NET MAUI Maps control offers endless possibilities for creating dynamic and engaging map applications.
Adding OSM on .NET MAUI Maps
OpenStreetMap is a free tile/image provider that returns map tiles for requested coordinates. It is one of the tile providers that can be used with the .NET MAUI Maps control. The URL format of the OpenStreetMap provider can be found in the following code sample.
Note: Though the OpenStreetMap is free of cost, we recommend you check the licensing terms and conditions before using it.
Navigating different countries’ locations over the OSM layer
The UI navigation we are developing here offers a fascinating representation of the BRICS countries, which stands for five major emerging economies: Brazil, Russia, India, China, and South Africa. Despite their diverse economic and political systems, these countries are considered leading developing nations with high growth potential.
The navigation involves switching among these countries based on their geographical center point and flag representation. Following is the code to create the UI and navigation logic.
The XAML code defines a ContentPage that contains a scroll view and a grid. The grid is divided into two rows, where the first row has a map control, and the second row has a horizontal stack layout containing five buttons representing the BRICS countries.
<ScrollView>
<Grid RowDefinitions="50,*">
<maps:SfMaps Grid.Row="1" x:Name="bricsmap">
</maps:SfMaps>
<HorizontalStackLayout>
<Button Text="Brazil" Clicked="Button_Clicked"/>
<Button Text="Russia" Clicked="Button_Clicked"/>
<Button Text="India" Clicked="Button_Clicked"/>
<Button Text="China" Clicked="Button_Clicked"/>
<Button Text="South Africa" Clicked="Button_Clicked"/>
</HorizontalStackLayout>
</Grid>
</ScrollView>
The Maps control is defined in the XAML using Syncfusion.Maui.Maps namespace. The OpenStreetMap tile provider is specified in the MapTileLayer UrlTemplate.
<ScrollView>
<Grid RowDefinitions="50,*">
<maps:SfMaps Grid.Row="1" x:Name="bricsmap">
<maps:SfMaps.Layer>
<maps:MapTileLayer UrlTemplate="https://tile.openstreetmap.org/{z}/{x}/{y}.png">
</maps:MapTileLayer>
</maps:SfMaps.Layer>
</maps:SfMaps>
<HorizontalStackLayout>
<Button Text="Brazil" Clicked="Button_Clicked"/>
<Button Text="Russia" Clicked="Button_Clicked"/>
<Button Text="India" Clicked="Button_Clicked"/>
<Button Text="China" Clicked="Button_Clicked"/>
<Button Text="South Africa" Clicked="Button_Clicked"/>
</HorizontalStackLayout>
</Grid>
</ScrollView>
The MapZoomPanBehavior allows zooming and panning with a minimum zoom level of 3 and a maximum of 10.
<ScrollView>
<Grid RowDefinitions="50,*">
<maps:SfMaps Grid.Row="1" x:Name="bricsmap">
<maps:SfMaps.Layer>
<maps:MapTileLayer UrlTemplate="https://tile.openstreetmap.org/{z}/{x}/{y}.png">
<maps:MapTileLayer.ZoomPanBehavior>
<maps:MapZoomPanBehavior MinZoomLevel="3"
MaxZoomLevel="10"
EnableDoubleTapZooming="True"
ZoomLevel="3">
</maps:MapZoomPanBehavior>
</maps:MapTileLayer.ZoomPanBehavior>
</maps:MapTileLayer>
</maps:SfMaps.Layer>
</maps:SfMaps>
<HorizontalStackLayout>
<Button Text="Brazil" Clicked="Button_Clicked"/>
<Button Text="Russia" Clicked="Button_Clicked"/>
<Button Text="India" Clicked="Button_Clicked"/>
<Button Text="China" Clicked="Button_Clicked"/>
<Button Text="South Africa" Clicked="Button_Clicked"/>
</HorizontalStackLayout>
</Grid>
</ScrollView>
In the code behind, the MainPage constructor initializes the mapMarkers collection and adds a mapMarker. It sets the MarkerTemplate of the MapTileLayer to the CreateDataTemplate method with the argument India.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
mapMarkers.Add(mapMarker);
(this.bricsmap.Layer as MapTileLayer).Markers = mapMarkers;
mapMarker.Latitude = 23.4417;
mapMarker.Longitude = 79.9417;
(this.bricsmap.Layer as MapTileLayer).MarkerTemplate = CreateDataTemplate("india");
}
MapMarkerCollection mapMarkers = new MapMarkerCollection();
MapMarker mapMarker = new MapMarker();
}
The CreateDataTemplate method returns a new DataTemplate that contains an image control with a specified country name followed by the word flag.png. It is wrapped inside a StackLayout and then returned in a ViewCell.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
mapMarkers.Add(mapMarker);
(this.bricsmap.Layer as MapTileLayer).Markers = mapMarkers;
mapMarker.Latitude = 23.4417;
mapMarker.Longitude = 79.9417;
(this.bricsmap.Layer as MapTileLayer).MarkerTemplate = CreateDataTemplate("india");
}
private DataTemplate CreateDataTemplate(string countryName)
{
return new DataTemplate(() =>
{
var stackLayout = new StackLayout();
var image = new Image
{
Source = countryName + "flag.png",
WidthRequest = 20,
HeightRequest = 20
};
stackLayout.Add(image);
return new ViewCell { View = stackLayout };
});
}
MapMarkerCollection mapMarkers = new MapMarkerCollection();
MapMarker mapMarker = new MapMarker();
}
The Button_Clicked event handler sets the latitude and longitude of the mapMarker to the coordinates of the clicked country. It then sets the MarkerTemplate of the MapTileLayer to the CreateDataTemplate method with the argument of the corresponding country name. Finally, it centers the MapTileLayer on the new location.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
mapMarkers.Add(mapMarker);
(this.bricsmap.Layer as MapTileLayer).Markers = mapMarkers;
mapMarker.Latitude = 23.4417;
mapMarker.Longitude = 79.9417;
(this.bricsmap.Layer as MapTileLayer).MarkerTemplate = CreateDataTemplate("india");
}
private DataTemplate CreateDataTemplate(string countryName)
{
return new DataTemplate(() =>
{
var stackLayout = new StackLayout();
var image = new Image
{
Source = countryName + "flag.png",
WidthRequest = 20,
HeightRequest = 20
};
stackLayout.Add(image);
return new ViewCell { View = stackLayout };
});
}
MapMarkerCollection mapMarkers = new MapMarkerCollection();
MapMarker mapMarker = new MapMarker();
private void Button_Clicked(object sender, EventArgs e)
{
var tileLayer = this.bricsmap.Layer as MapTileLayer;
if (sender is Button button)
{
if (button.Text == "Brazil")
{
mapMarker.Latitude = -15.8083;
mapMarker.Longitude = -49.3083;
tileLayer.MarkerTemplate = CreateDataTemplate("brazil");
}
if (button.Text == "Russia")
{
mapMarker.Latitude = 62.1983;
mapMarker.Longitude = 96.7017;
tileLayer.MarkerTemplate = CreateDataTemplate("russia");
}
if (button.Text == "India")
{
mapMarker.Latitude = 23.4417;
mapMarker.Longitude = 79.9417;
tileLayer.MarkerTemplate = CreateDataTemplate("india");
}
if (button.Text == "China")
{
mapMarker.Latitude = 34.6292;
mapMarker.Longitude = 103.3681;
tileLayer.MarkerTemplate = CreateDataTemplate("china");
}
if (button.Text == "South Africa")
{
mapMarker.Latitude = -28.2697;
mapMarker.Longitude = 28.3383;
tileLayer.MarkerTemplate = CreateDataTemplate("southafrica");
}
tileLayer.Center = new MapLatLng(mapMarker.Latitude, mapMarker.Longitude);
}
}
}
Conclusion
Thank you for reading! In this article, we discussed using the TileLayer of .NET MAUI Maps to navigate locations on OSM. Give it a try and let us know your thoughts in the comments section.
Discover more features in the .NET MAUI Maps user guide and GitHub demos. You can also find our .NET MAUI demo apps on Google Play and the Microsoft Store.
Are you already a Syncfusion user? You can download the product setup here. If you’re not a Syncfusion user, you can download a free 30-day trial here.
If you have any questions or concerns, please contact us through our support forums, support portal, or feedback portal. We’re always here to help!