DEV Community

ilsonosli
ilsonosli

Posted on

.NET MAUI Map Data

So you want to use maps in your .NET MAUI application?

Image description

There is a great tutorial on Microsoft Learn to help you get started with maps using .NET MAUI here.

Once you have your map up and running, your next step is usually to want to visualize some data! The documentation gives us the following code to add pins to the map:

 protected override void OnAppearing()
  {
      base.OnAppearing();

      MyMap.Pins.Add(new Microsoft.Maui.Controls.Maps.Pin
      {
          Location = new Location(20.793062527, -156.336394697),
          Label = "Look I'm a Pin!"
      });
  }
Enter fullscreen mode Exit fullscreen mode

Which gives us the following awesome output:
Image description

This is great right? Well, yes! But!!

The usual coding paradigm for client .NET applications uses MVVM giving the ability to bind your data to the controls you are using. Unfortunately map pins do not allow this.

Lets get a hacky attempt at making the map bindable:

using System;
using System.Collections;
using System.Collections.ObjectModel;
using Microsoft.Maui.Maps;

namespace Kwakes
{
    public class BindableMap : Microsoft.Maui.Controls.Maps.Map
    {
        public static readonly BindableProperty PinSourceProperty =
            BindableProperty.Create("PinSource",
                typeof(IEnumerable),
                typeof(Microsoft.Maui.Controls.Maps.Map),
                null,
                propertyChanged: OnPinSourceChanged);

        public IEnumerable PinSource
        {
            get { return (IEnumerable)GetValue(PinSourceProperty); }
            set { SetValue(PinSourceProperty, value); }
        }



        static void OnPinSourceChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var map = bindable as BindableMap;

            if (oldValue != null)
                foreach (IMapPin pin in oldValue as IEnumerable)
                {
                    map.Pins.Remove(pin as Microsoft.Maui.Controls.Maps.Pin);
                }

            if (newValue != null)
                foreach (IMapPin pin in newValue as IEnumerable)
                {
                    map.Pins.Add(pin as Microsoft.Maui.Controls.Maps.Pin);
                }
        }

        public BindableMap() : base(new MapSpan(new Location(20.793062527, -156.336394697), 0.5, 0.5))
        {

        }

        public void BindablePins_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            foreach (IMapPin pin in e.OldItems ?? new List<IMapPin>())
            {
                this.Pins.Remove(pin as Microsoft.Maui.Controls.Maps.Pin);
            }

            foreach (IMapPin pin in e?.NewItems ?? new List<IMapPin>())
            {
                this.Pins.Add(pin as Microsoft.Maui.Controls.Maps.Pin);
            }
        }

    }
}

Enter fullscreen mode Exit fullscreen mode

Here we have created a subclass of the Map control and added a PinSource bindable property. On the change event of the bound data we handle removing and adding the relevant pins.

And now we can bind to the PinSource property, like this:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:kwakes="clr-namespace:Kwakes"
             x:Class="Kwakes.MainPage">

   <kwakes:BindableMap x:Name="MyMap" PinSource="{Binding ThePins}">
    </kwakes:BindableMap>

</ContentPage>

Enter fullscreen mode Exit fullscreen mode

Giving us the following amazing pins on our map!

Image description

HOORAY!

This does not account for things like ObservableCollections and interaction but its a great start towards handling the pin data in your ViewModel.

Please do let me know if this is helpful or if you have any comments or feedback!

IlsonoslI

Top comments (1)

Collapse
 
symbiogenesis profile image
Edward Miller

I solved the same problem here:

dev.to/symbiogenesis/use-net-maui-...