Navigating Location on OSM Layer Using the TileLayer of .NET MAUI Maps
Detailed Blog page Skeleton loader
Navigating Location on OSM Layer Using the TileLayer of .NET MAUI Maps

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);
        }
    }

}
Navigating different countries with the OSM layer final output
Navigating different countries with the OSM layer using .NET MAUI Maps TileLayer

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 forumssupport portal, or feedback portal. We’re always here to help!

Test Flight
App Center Badge
Google Play Store Badge
Microsoft Badge
Github Store Badge

Related blogs

Be the first to get updates

Selva Ganapathy Kathiresan

Meet the Author

Selva Ganapathy Kathiresan

Selva Ganapathy Kathiresan is an Assistant General Manager at Syncfusion and a Microsoft MVP (2014), who sees through the development of Mobile and Desktop components. His areas of expertise are React, .NET MAUI, Xamarin, WPF, UWP and other .NET Frameworks.

Comments (1)

Already tried and do like BUT there is no way provided to save or print the result. Would use if at least one of these were provided. Until then will continue to use a Blazor control that does both.

Comments are closed.