Xamarin.Forms Map Pins
The Xamarin.Forms Map
control allows locations to be marked with Pin
objects. A Pin
is a map marker that opens an information window when tapped:
When a Pin
object is added to the Map.Pins
collection, the pin is rendered on the map.
The Pin
class has the following properties:
Address
, of typestring
, which typically represents the address for the pin location. However, it can be anystring
content, not just an address.Label
, of typestring
, which typically represents the pin title.Position
, of typePosition
, which represents the latitude and longitude of the pin.Type
, of typePinType
, which represents the type of pin.
These properties are backed by BindableProperty
objects, which means a Pin
can be the target of data bindings. For more information about data binding Pin
objects, see Display a pin collection.
In addition, the Pin
class defines MarkerClicked
and InfoWindowClicked
events. The MarkerClicked
event is fired when a pin is tapped, and the InfoWindowClicked
event is fired when the information window is tapped. The PinClickedEventArgs
object that accompanies both events has a single HideInfoWindow
property, of type bool
.
Display a pin
A Pin
can be added to a Map
in XAML:
<ContentPage ...
xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps">
<maps:Map x:Name="map"
IsShowingUser="True"
MoveToLastRegionOnLayoutChange="False">
<x:Arguments>
<maps:MapSpan>
<x:Arguments>
<maps:Position>
<x:Arguments>
<x:Double>36.9628066</x:Double>
<x:Double>-122.0194722</x:Double>
</x:Arguments>
</maps:Position>
<x:Double>0.01</x:Double>
<x:Double>0.01</x:Double>
</x:Arguments>
</maps:MapSpan>
</x:Arguments>
<maps:Map.Pins>
<maps:Pin Label="Santa Cruz"
Address="The city with a boardwalk"
Type="Place">
<maps:Pin.Position>
<maps:Position>
<x:Arguments>
<x:Double>36.9628066</x:Double>
<x:Double>-122.0194722</x:Double>
</x:Arguments>
</maps:Position>
</maps:Pin.Position>
</maps:Pin>
</maps:Map.Pins>
</maps:Map>
</ContentPage>
This XAML creates a Map
object that shows the region that is specified by the MapSpan
object. The MapSpan
object is centered on the latitude and longitude represented by a Position
object, which extends 0.01 latitude and longitude degrees. A Pin
object is added to the Map.Pins
collection, and drawn on the Map
at the location specified by its Position
property. For information about the Position
struct, see Map Position and Distance. For information about passing arguments in XAML to objects that lack default constructors, see Passing Arguments in XAML.
The equivalent C# code is:
using Xamarin.Forms.Maps;
// ...
Map map = new Map
{
// ...
};
Pin pin = new Pin
{
Label = "Santa Cruz",
Address = "The city with a boardwalk",
Type = PinType.Place,
Position = new Position(36.9628066, -122.0194722)
};
map.Pins.Add(pin);
Warning
Failure to set the Pin.Label
property will result in an ArgumentException
being thrown when the Pin
is added to a Map
.
This example code results in a single pin being rendered on a map:
Interact with a pin
By default, when a Pin
is tapped its information window is displayed:
Tapping elsewhere on the map closes the information window.
The Pin
class defines a MarkerClicked
event, which is fired when a Pin
is tapped. It's not necessary to handle this event to display the information window. Instead, this event should be handled when there's a requirement to be notified that a specific pin has been tapped.
The Pin
class also defines a InfoWindowClicked
event that's fired when an information window is tapped. This event should be handled when there's a requirement to be notified that a specific information window has been tapped.
The following code shows an example of handling these events:
using Xamarin.Forms.Maps;
// ...
Pin boardwalkPin = new Pin
{
Position = new Position(36.9641949, -122.0177232),
Label = "Boardwalk",
Address = "Santa Cruz",
Type = PinType.Place
};
boardwalkPin.MarkerClicked += async (s, args) =>
{
args.HideInfoWindow = true;
string pinName = ((Pin)s).Label;
await DisplayAlert("Pin Clicked", $"{pinName} was clicked.", "Ok");
};
Pin wharfPin = new Pin
{
Position = new Position(36.9571571, -122.0173544),
Label = "Wharf",
Address = "Santa Cruz",
Type = PinType.Place
};
wharfPin.InfoWindowClicked += async (s, args) =>
{
string pinName = ((Pin)s).Label;
await DisplayAlert("Info Window Clicked", $"The info window was clicked for {pinName}.", "Ok");
};
The PinClickedEventArgs
object that accompanies both events has a single HideInfoWindow
property, of type bool
. When this property is set to true
inside an event handler, the information window will be hidden.
Pin types
Pin
objects include a Type
property, of type PinType
, which represents the type of pin. The PinType
enumeration defines the following members:
Generic
, represents a generic pin.Place
, represents a pin for a place.SavedPin
, represents a pin for a saved location.SearchResult
, represents a pin for a search result.
However, setting the Pin.Type
property to any PinType
member does not change the appearance of the rendered pin. Instead, you must create a custom renderer to customize pin appearance. For more information, see Customizing a map pin.
Display a pin collection
The Map
class defines the following properties:
ItemsSource
, of typeIEnumerable
, which specifies the collection ofIEnumerable
items to be displayed.ItemTemplate
, of typeDataTemplate
, which specifies theDataTemplate
to apply to each item in the collection of displayed items.ItemTemplateSelector
, of typeDataTemplateSelector
, which specifies theDataTemplateSelector
that will be used to choose aDataTemplate
for an item at runtime.
Important
The ItemTemplate
property takes precedence when both the ItemTemplate
and ItemTemplateSelector
properties are set.
A Map
can be populated with pins by using data binding to bind its ItemsSource
property to an IEnumerable
collection:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"
x:Class="WorkingWithMaps.PinItemsSourcePage">
<Grid>
...
<maps:Map x:Name="map"
ItemsSource="{Binding Locations}">
<maps:Map.ItemTemplate>
<DataTemplate>
<maps:Pin Position="{Binding Position}"
Address="{Binding Address}"
Label="{Binding Description}" />
</DataTemplate>
</maps:Map.ItemTemplate>
</maps:Map>
...
</Grid>
</ContentPage>
The ItemsSource
property data binds to the Locations
property of the connected viewmodel, which returns an ObservableCollection
of Location
objects, which is a custom type. Each Location
object defines Address
and Description
properties, of type string
, and a Position
property, of type Position
.
The appearance of each item in the IEnumerable
collection is defined by setting the ItemTemplate
property to a DataTemplate
that contains a Pin
object that data binds to appropriate properties.
The following screenshots show a Map
displaying a Pin
collection using data binding:
Choose item appearance at runtime
The appearance of each item in the IEnumerable
collection can be chosen at runtime, based on the item value, by setting the ItemTemplateSelector
property to a DataTemplateSelector
:
<ContentPage ...
xmlns:local="clr-namespace:WorkingWithMaps"
xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps">
<ContentPage.Resources>
<local:MapItemTemplateSelector x:Key="MapItemTemplateSelector">
<local:MapItemTemplateSelector.DefaultTemplate>
<DataTemplate>
<maps:Pin Position="{Binding Position}"
Address="{Binding Address}"
Label="{Binding Description}" />
</DataTemplate>
</local:MapItemTemplateSelector.DefaultTemplate>
<local:MapItemTemplateSelector.XamarinTemplate>
<DataTemplate>
<!-- Change the property values, or the properties that are bound to. -->
<maps:Pin Position="{Binding Position}"
Address="{Binding Address}"
Label="Xamarin!" />
</DataTemplate>
</local:MapItemTemplateSelector.XamarinTemplate>
</local:MapItemTemplateSelector>
</ContentPage.Resources>
<Grid>
...
<maps:Map x:Name="map"
ItemsSource="{Binding Locations}"
ItemTemplateSelector="{StaticResource MapItemTemplateSelector}" />
...
</Grid>
</ContentPage>
The following example shows the MapItemTemplateSelector
class:
public class MapItemTemplateSelector : DataTemplateSelector
{
public DataTemplate DefaultTemplate { get; set; }
public DataTemplate XamarinTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return ((Location)item).Address.Contains("San Francisco") ? XamarinTemplate : DefaultTemplate;
}
}
The MapItemTemplateSelector
class defines DefaultTemplate
and XamarinTemplate
DataTemplate
properties that are set to different data templates. The OnSelectTemplate
method returns the XamarinTemplate
, which displays "Xamarin" as a label when a Pin
is tapped, when the item has an address that contains "San Francisco". When the item doesn't have an address that contains "San Francisco", the OnSelectTemplate
method returns the DefaultTemplate
.
Note
A use case for this functionality is binding properties of sub-classed Pin
objects to different properties, based on the Pin
sub-type.
For more information about data template selectors, see Creating a Xamarin.Forms DataTemplateSelector.