So you want to use maps in your .NET MAUI application?
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!"
});
}
Which gives us the following awesome output:
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);
}
}
}
}
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>
Giving us the following amazing pins on our map!
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)
I solved the same problem here:
dev.to/symbiogenesis/use-net-maui-...