diff --git a/src/Controls/Maps/src/HandlerImpl/Pin.Impl.cs b/src/Controls/Maps/src/HandlerImpl/Pin.Impl.cs
index a8c4359d7aa4..79a6b48df7b1 100644
--- a/src/Controls/Maps/src/HandlerImpl/Pin.Impl.cs
+++ b/src/Controls/Maps/src/HandlerImpl/Pin.Impl.cs
@@ -4,5 +4,9 @@ namespace Microsoft.Maui.Controls.Maps
{
public partial class Pin : IMapPin
{
+ ///
+ /// Explicit implementation of IMapPin.ImageSource to convert from ImageSource to IImageSource.
+ ///
+ IImageSource? IMapPin.ImageSource => ImageSource;
}
}
diff --git a/src/Controls/Maps/src/Pin.cs b/src/Controls/Maps/src/Pin.cs
index dc9120108b91..b4b065cb3abd 100644
--- a/src/Controls/Maps/src/Pin.cs
+++ b/src/Controls/Maps/src/Pin.cs
@@ -30,6 +30,9 @@ public partial class Pin : Element
/// Bindable property for .
public static readonly BindableProperty ClusteringIdentifierProperty = BindableProperty.Create(nameof(ClusteringIdentifier), typeof(string), typeof(Pin), DefaultClusteringIdentifier);
+ /// Bindable property for .
+ public static readonly BindableProperty ImageSourceProperty = BindableProperty.Create(nameof(ImageSource), typeof(ImageSource), typeof(Pin), default(ImageSource));
+
private object? _markerId;
///
@@ -81,6 +84,22 @@ public PinType Type
set { SetValue(TypeProperty, value); }
}
+ ///
+ /// Gets or sets the custom image source for this pin's icon.
+ /// When set, this image will be used instead of the default platform pin icon.
+ /// This is a bindable property.
+ ///
+ ///
+ /// Supported image sources include file-based images, embedded resources, URIs, and streams.
+ /// The image will be scaled by the underlying platform to a platform-defined size (32x32 points on iOS, 64x64 pixels on Android).
+ /// Provide images that look clear when scaled to these sizes.
+ ///
+ public ImageSource? ImageSource
+ {
+ get { return (ImageSource?)GetValue(ImageSourceProperty); }
+ set { SetValue(ImageSourceProperty, value); }
+ }
+
///
/// Gets or sets the platform counterpart of this pin element.
///
diff --git a/src/Controls/Maps/src/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Controls/Maps/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
index ddbf4e1c505d..6e5dcb340de6 100644
--- a/src/Controls/Maps/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
+++ b/src/Controls/Maps/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
@@ -18,6 +18,8 @@ Microsoft.Maui.Controls.Maps.MapElement.ZIndex.get -> int
Microsoft.Maui.Controls.Maps.MapElement.ZIndex.set -> void
Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifier.get -> string!
Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifier.set -> void
+Microsoft.Maui.Controls.Maps.Pin.ImageSource.get -> Microsoft.Maui.Controls.ImageSource?
+Microsoft.Maui.Controls.Maps.Pin.ImageSource.set -> void
Microsoft.Maui.Controls.Maps.Polygon.PolygonClicked -> System.EventHandler?
Microsoft.Maui.Controls.Maps.Polyline.PolylineClicked -> System.EventHandler?
const Microsoft.Maui.Controls.Maps.Pin.DefaultClusteringIdentifier = "maui_default_cluster" -> string!
@@ -26,3 +28,4 @@ static readonly Microsoft.Maui.Controls.Maps.Map.RegionProperty -> Microsoft.Mau
static readonly Microsoft.Maui.Controls.Maps.MapElement.IsVisibleProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.Maps.MapElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifierProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Maps.Pin.ImageSourceProperty -> Microsoft.Maui.Controls.BindableProperty!
diff --git a/src/Controls/Maps/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Controls/Maps/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
index ddbf4e1c505d..6e5dcb340de6 100644
--- a/src/Controls/Maps/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
+++ b/src/Controls/Maps/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
@@ -18,6 +18,8 @@ Microsoft.Maui.Controls.Maps.MapElement.ZIndex.get -> int
Microsoft.Maui.Controls.Maps.MapElement.ZIndex.set -> void
Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifier.get -> string!
Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifier.set -> void
+Microsoft.Maui.Controls.Maps.Pin.ImageSource.get -> Microsoft.Maui.Controls.ImageSource?
+Microsoft.Maui.Controls.Maps.Pin.ImageSource.set -> void
Microsoft.Maui.Controls.Maps.Polygon.PolygonClicked -> System.EventHandler?
Microsoft.Maui.Controls.Maps.Polyline.PolylineClicked -> System.EventHandler?
const Microsoft.Maui.Controls.Maps.Pin.DefaultClusteringIdentifier = "maui_default_cluster" -> string!
@@ -26,3 +28,4 @@ static readonly Microsoft.Maui.Controls.Maps.Map.RegionProperty -> Microsoft.Mau
static readonly Microsoft.Maui.Controls.Maps.MapElement.IsVisibleProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.Maps.MapElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifierProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Maps.Pin.ImageSourceProperty -> Microsoft.Maui.Controls.BindableProperty!
diff --git a/src/Controls/Maps/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Controls/Maps/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
index ddbf4e1c505d..6e5dcb340de6 100644
--- a/src/Controls/Maps/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
+++ b/src/Controls/Maps/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
@@ -18,6 +18,8 @@ Microsoft.Maui.Controls.Maps.MapElement.ZIndex.get -> int
Microsoft.Maui.Controls.Maps.MapElement.ZIndex.set -> void
Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifier.get -> string!
Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifier.set -> void
+Microsoft.Maui.Controls.Maps.Pin.ImageSource.get -> Microsoft.Maui.Controls.ImageSource?
+Microsoft.Maui.Controls.Maps.Pin.ImageSource.set -> void
Microsoft.Maui.Controls.Maps.Polygon.PolygonClicked -> System.EventHandler?
Microsoft.Maui.Controls.Maps.Polyline.PolylineClicked -> System.EventHandler?
const Microsoft.Maui.Controls.Maps.Pin.DefaultClusteringIdentifier = "maui_default_cluster" -> string!
@@ -26,3 +28,4 @@ static readonly Microsoft.Maui.Controls.Maps.Map.RegionProperty -> Microsoft.Mau
static readonly Microsoft.Maui.Controls.Maps.MapElement.IsVisibleProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.Maps.MapElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifierProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Maps.Pin.ImageSourceProperty -> Microsoft.Maui.Controls.BindableProperty!
diff --git a/src/Controls/Maps/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt b/src/Controls/Maps/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
index ddbf4e1c505d..6e5dcb340de6 100644
--- a/src/Controls/Maps/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
+++ b/src/Controls/Maps/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
@@ -18,6 +18,8 @@ Microsoft.Maui.Controls.Maps.MapElement.ZIndex.get -> int
Microsoft.Maui.Controls.Maps.MapElement.ZIndex.set -> void
Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifier.get -> string!
Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifier.set -> void
+Microsoft.Maui.Controls.Maps.Pin.ImageSource.get -> Microsoft.Maui.Controls.ImageSource?
+Microsoft.Maui.Controls.Maps.Pin.ImageSource.set -> void
Microsoft.Maui.Controls.Maps.Polygon.PolygonClicked -> System.EventHandler?
Microsoft.Maui.Controls.Maps.Polyline.PolylineClicked -> System.EventHandler?
const Microsoft.Maui.Controls.Maps.Pin.DefaultClusteringIdentifier = "maui_default_cluster" -> string!
@@ -26,3 +28,4 @@ static readonly Microsoft.Maui.Controls.Maps.Map.RegionProperty -> Microsoft.Mau
static readonly Microsoft.Maui.Controls.Maps.MapElement.IsVisibleProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.Maps.MapElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifierProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Maps.Pin.ImageSourceProperty -> Microsoft.Maui.Controls.BindableProperty!
diff --git a/src/Controls/Maps/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Controls/Maps/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
index ddbf4e1c505d..6e5dcb340de6 100644
--- a/src/Controls/Maps/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
+++ b/src/Controls/Maps/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
@@ -18,6 +18,8 @@ Microsoft.Maui.Controls.Maps.MapElement.ZIndex.get -> int
Microsoft.Maui.Controls.Maps.MapElement.ZIndex.set -> void
Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifier.get -> string!
Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifier.set -> void
+Microsoft.Maui.Controls.Maps.Pin.ImageSource.get -> Microsoft.Maui.Controls.ImageSource?
+Microsoft.Maui.Controls.Maps.Pin.ImageSource.set -> void
Microsoft.Maui.Controls.Maps.Polygon.PolygonClicked -> System.EventHandler?
Microsoft.Maui.Controls.Maps.Polyline.PolylineClicked -> System.EventHandler?
const Microsoft.Maui.Controls.Maps.Pin.DefaultClusteringIdentifier = "maui_default_cluster" -> string!
@@ -26,3 +28,4 @@ static readonly Microsoft.Maui.Controls.Maps.Map.RegionProperty -> Microsoft.Mau
static readonly Microsoft.Maui.Controls.Maps.MapElement.IsVisibleProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.Maps.MapElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifierProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Maps.Pin.ImageSourceProperty -> Microsoft.Maui.Controls.BindableProperty!
diff --git a/src/Controls/Maps/src/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Controls/Maps/src/PublicAPI/net/PublicAPI.Unshipped.txt
index ddbf4e1c505d..6e5dcb340de6 100644
--- a/src/Controls/Maps/src/PublicAPI/net/PublicAPI.Unshipped.txt
+++ b/src/Controls/Maps/src/PublicAPI/net/PublicAPI.Unshipped.txt
@@ -18,6 +18,8 @@ Microsoft.Maui.Controls.Maps.MapElement.ZIndex.get -> int
Microsoft.Maui.Controls.Maps.MapElement.ZIndex.set -> void
Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifier.get -> string!
Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifier.set -> void
+Microsoft.Maui.Controls.Maps.Pin.ImageSource.get -> Microsoft.Maui.Controls.ImageSource?
+Microsoft.Maui.Controls.Maps.Pin.ImageSource.set -> void
Microsoft.Maui.Controls.Maps.Polygon.PolygonClicked -> System.EventHandler?
Microsoft.Maui.Controls.Maps.Polyline.PolylineClicked -> System.EventHandler?
const Microsoft.Maui.Controls.Maps.Pin.DefaultClusteringIdentifier = "maui_default_cluster" -> string!
@@ -26,3 +28,4 @@ static readonly Microsoft.Maui.Controls.Maps.Map.RegionProperty -> Microsoft.Mau
static readonly Microsoft.Maui.Controls.Maps.MapElement.IsVisibleProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.Maps.MapElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifierProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Maps.Pin.ImageSourceProperty -> Microsoft.Maui.Controls.BindableProperty!
diff --git a/src/Controls/Maps/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt b/src/Controls/Maps/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt
index ddbf4e1c505d..6e5dcb340de6 100644
--- a/src/Controls/Maps/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt
+++ b/src/Controls/Maps/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt
@@ -18,6 +18,8 @@ Microsoft.Maui.Controls.Maps.MapElement.ZIndex.get -> int
Microsoft.Maui.Controls.Maps.MapElement.ZIndex.set -> void
Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifier.get -> string!
Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifier.set -> void
+Microsoft.Maui.Controls.Maps.Pin.ImageSource.get -> Microsoft.Maui.Controls.ImageSource?
+Microsoft.Maui.Controls.Maps.Pin.ImageSource.set -> void
Microsoft.Maui.Controls.Maps.Polygon.PolygonClicked -> System.EventHandler?
Microsoft.Maui.Controls.Maps.Polyline.PolylineClicked -> System.EventHandler?
const Microsoft.Maui.Controls.Maps.Pin.DefaultClusteringIdentifier = "maui_default_cluster" -> string!
@@ -26,3 +28,4 @@ static readonly Microsoft.Maui.Controls.Maps.Map.RegionProperty -> Microsoft.Mau
static readonly Microsoft.Maui.Controls.Maps.MapElement.IsVisibleProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.Maps.MapElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.Maps.Pin.ClusteringIdentifierProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Maps.Pin.ImageSourceProperty -> Microsoft.Maui.Controls.BindableProperty!
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/CustomPinIconGallery.xaml b/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/CustomPinIconGallery.xaml
new file mode 100644
index 000000000000..d440e026c28e
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/CustomPinIconGallery.xaml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/CustomPinIconGallery.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/CustomPinIconGallery.xaml.cs
new file mode 100644
index 000000000000..0d83a2eb96d4
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/CustomPinIconGallery.xaml.cs
@@ -0,0 +1,62 @@
+using System;
+using Microsoft.Maui.Controls;
+using Microsoft.Maui.Controls.Maps;
+using Microsoft.Maui.Devices.Sensors;
+using Microsoft.Maui.Maps;
+
+namespace Maui.Controls.Sample.Pages.MapsGalleries
+{
+ public partial class CustomPinIconGallery : ContentPage
+ {
+ public CustomPinIconGallery()
+ {
+ InitializeComponent();
+
+ // Center on Seattle
+ CustomPinMap.MoveToRegion(MapSpan.FromCenterAndRadius(
+ new Microsoft.Maui.Devices.Sensors.Location(47.6062, -122.3321),
+ Distance.FromMiles(5)));
+ }
+
+ void OnAddCustomPinsClicked(object? sender, EventArgs e)
+ {
+ // Add pin with custom icon from an image file in the app bundle
+ var customPin1 = new Pin
+ {
+ Label = "Custom Icon Pin",
+ Address = "Using app bundle image",
+ Location = new Microsoft.Maui.Devices.Sensors.Location(47.6062, -122.3321),
+ ImageSource = ImageSource.FromFile("dotnet_bot.png")
+ };
+ CustomPinMap.Pins.Add(customPin1);
+
+ // Add another custom pin at different location
+ var customPin2 = new Pin
+ {
+ Label = "Another Custom Pin",
+ Address = "Also using custom image",
+ Location = new Microsoft.Maui.Devices.Sensors.Location(47.62, -122.35),
+ ImageSource = ImageSource.FromFile("dotnet_bot.png")
+ };
+ CustomPinMap.Pins.Add(customPin2);
+ }
+
+ void OnAddDefaultPinClicked(object? sender, EventArgs e)
+ {
+ // Add a regular pin without custom icon for comparison
+ var defaultPin = new Pin
+ {
+ Label = "Default Pin",
+ Address = "Standard marker icon",
+ Location = new Microsoft.Maui.Devices.Sensors.Location(47.59, -122.31),
+ Type = PinType.Place
+ };
+ CustomPinMap.Pins.Add(defaultPin);
+ }
+
+ void OnClearClicked(object? sender, EventArgs e)
+ {
+ CustomPinMap.Pins.Clear();
+ }
+ }
+}
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/MapsGallery.cs b/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/MapsGallery.cs
index e90a369107b3..0e61dff497a8 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/MapsGallery.cs
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/MapsGallery.cs
@@ -18,6 +18,8 @@ public MapsGallery()
GalleryBuilder.NavButton("Map Pins", () => new MapPinsGallery(), Navigation),
GalleryBuilder.NavButton("Pins ItemsSource", () => new PinItemsSourceGallery(), Navigation),
GalleryBuilder.NavButton("Pin Clustering", () => new ClusteringGallery(), Navigation),
+
+ GalleryBuilder.NavButton("Custom Pin Icons", () => new CustomPinIconGallery(), Navigation),
GalleryBuilder.NavButton("Circle", () => new CircleGallery(), Navigation),
GalleryBuilder.NavButton("Polygon", () => new PolygonsGallery(), Navigation),
GalleryBuilder.NavButton("Element Visibility & ZIndex", () => new MapElementVisibilityGallery(), Navigation),
diff --git a/src/Controls/tests/Core.UnitTests/PinTests.cs b/src/Controls/tests/Core.UnitTests/PinTests.cs
index 9d721baf5a53..0f95906def65 100644
--- a/src/Controls/tests/Core.UnitTests/PinTests.cs
+++ b/src/Controls/tests/Core.UnitTests/PinTests.cs
@@ -114,5 +114,64 @@ public void Label()
Assert.True(signaled);
}
+
+ [Fact]
+ public void ImageSourceDefaultsToNull()
+ {
+ var pin = new Pin();
+ Assert.Null(pin.ImageSource);
+ }
+
+ [Fact]
+ public void ImageSourceCanBeSet()
+ {
+ var pin = new Pin
+ {
+ ImageSource = ImageSource.FromFile("test.png")
+ };
+
+ Assert.NotNull(pin.ImageSource);
+ Assert.IsType(pin.ImageSource);
+ }
+
+ [Fact]
+ public void ImageSourcePropertyChanged()
+ {
+ var pin = new Pin();
+
+ bool signaled = false;
+ pin.PropertyChanged += (sender, args) =>
+ {
+ if (args.PropertyName == "ImageSource")
+ signaled = true;
+ };
+
+ pin.ImageSource = ImageSource.FromFile("test.png");
+
+ Assert.True(signaled);
+ }
+
+ [Fact]
+ public void ImageSourceBindableProperty()
+ {
+ var pin = new Pin();
+ pin.SetValue(Pin.ImageSourceProperty, ImageSource.FromFile("bound.png"));
+
+ Assert.NotNull(pin.ImageSource);
+ Assert.IsType(pin.ImageSource);
+ }
+
+ [Fact]
+ public void IMapPinImageSourceReturnsValue()
+ {
+ var pin = new Pin
+ {
+ ImageSource = ImageSource.FromFile("test.png")
+ };
+
+ // Access through interface to test explicit implementation
+ var mapPin = (Microsoft.Maui.Maps.IMapPin)pin;
+ Assert.NotNull(mapPin.ImageSource);
+ }
}
}
diff --git a/src/Core/maps/src/Core/IMapPin.cs b/src/Core/maps/src/Core/IMapPin.cs
index 199ece0a86fd..58b85dd91541 100644
--- a/src/Core/maps/src/Core/IMapPin.cs
+++ b/src/Core/maps/src/Core/IMapPin.cs
@@ -35,6 +35,12 @@ public interface IMapPin : IElement
/// This should typically not be set by the developer. Doing so might result in unpredictable behavior.
object? MarkerId { get; set; }
+ ///
+ /// Gets the custom image source for this pin's icon.
+ ///
+ /// When set, this image will be used instead of the default platform pin icon.
+ IImageSource? ImageSource { get; }
+
///
/// Sends a marker click event.
///
diff --git a/src/Core/maps/src/Handlers/Map/MapHandler.Android.cs b/src/Core/maps/src/Handlers/Map/MapHandler.Android.cs
index 276edf5871ee..6e70c8407d36 100644
--- a/src/Core/maps/src/Handlers/Map/MapHandler.Android.cs
+++ b/src/Core/maps/src/Handlers/Map/MapHandler.Android.cs
@@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using Android.Gms.Common.Apis;
using Android.Gms.Maps;
@@ -24,6 +25,8 @@
using ACircle = Android.Gms.Maps.Model.Circle;
using APolygon = Android.Gms.Maps.Model.Polygon;
using APolyline = Android.Gms.Maps.Model.Polyline;
+using ADrawable = Android.Graphics.Drawables.Drawable;
+using ABitmapDrawable = Android.Graphics.Drawables.BitmapDrawable;
using Math = System.Math;
namespace Microsoft.Maui.Maps.Handlers
@@ -44,6 +47,8 @@ public partial class MapHandler : ViewHandler
List? _clusters;
Dictionary? _clusterMarkers;
+ CancellationTokenSource? _addPinsCts;
+
public GoogleMap? Map { get; private set; }
static Bundle? s_bundle;
@@ -598,6 +603,11 @@ void AddPins(IList pins)
if (Map == null || MauiContext == null)
return;
+ // Cancel any previously running pin additions to avoid stale markers
+ _addPinsCts?.Cancel();
+ _addPinsCts = new CancellationTokenSource();
+ var ct = _addPinsCts.Token;
+
if (_markers == null)
_markers = new List();
@@ -666,21 +676,7 @@ void AddPins(IList pins)
foreach (var p in pins)
{
IMapPin pin = (IMapPin)p;
- Marker? marker;
-
- var pinHandler = pin.ToHandler(MauiContext);
- if (pinHandler is IMapPinHandler iMapPinHandler)
- {
- marker = Map.AddMarker(iMapPinHandler.PlatformView);
- if (marker == null)
- {
- throw new System.Exception("Map.AddMarker returned null");
- }
- // associate pin with marker for later lookup in event handlers
- pin.MarkerId = marker.Id;
- _markers.Add(marker!);
- }
-
+ AddPinAsync(pin, ct).FireAndForget();
}
_pins = null;
}
@@ -730,6 +726,101 @@ void AddPins(IList pins)
}
}
+ async Task AddPinAsync(IMapPin pin, CancellationToken ct)
+ {
+ if (Map == null || MauiContext == null)
+ return;
+
+ var pinHandler = pin.ToHandler(MauiContext);
+ if (pinHandler is not IMapPinHandler iMapPinHandler)
+ return;
+
+ var markerOptions = iMapPinHandler.PlatformView;
+
+ // Load custom image if specified
+ if (pin.ImageSource != null)
+ {
+ try
+ {
+ var result = await pin.ImageSource.GetPlatformImageAsync(MauiContext);
+ if (ct.IsCancellationRequested || result?.Value is not ADrawable drawable)
+ return;
+
+ var bitmap = DrawableToBitmap(drawable);
+ if (bitmap != null)
+ {
+ markerOptions.SetIcon(BitmapDescriptorFactory.FromBitmap(bitmap));
+ }
+ }
+ catch (System.Exception ex)
+ {
+ var logger = MauiContext?.Services?.GetService>();
+ logger?.LogWarning(ex, "Failed to load custom pin icon");
+ }
+ }
+
+ // Re-check after async operation since handler may have been disconnected
+ if (ct.IsCancellationRequested || Map == null || MauiContext == null)
+ return;
+
+ var marker = Map.AddMarker(markerOptions);
+ if (marker == null)
+ {
+ throw new System.Exception("Map.AddMarker returned null");
+ }
+ // associate pin with marker for later lookup in event handlers
+ pin.MarkerId = marker.Id;
+
+ _markers ??= new List();
+ _markers.Add(marker);
+ }
+
+ static ABitmap? DrawableToBitmap(ADrawable drawable)
+ {
+ if (drawable is ABitmapDrawable bitmapDrawable && bitmapDrawable.Bitmap != null)
+ {
+ return ScaleBitmap(bitmapDrawable.Bitmap, 64, 64); // 64x64 pixels
+ }
+
+ int width = drawable.IntrinsicWidth;
+ int height = drawable.IntrinsicHeight;
+
+ if (width <= 0 || height <= 0)
+ {
+ width = 64;
+ height = 64;
+ }
+
+ var bitmap = ABitmap.CreateBitmap(width, height, ABitmap.Config.Argb8888!);
+ if (bitmap == null)
+ return null;
+
+ var canvas = new ACanvas(bitmap);
+ drawable.SetBounds(0, 0, canvas.Width, canvas.Height);
+ drawable.Draw(canvas);
+ canvas.Dispose();
+
+ var scaled = ScaleBitmap(bitmap, 64, 64);
+ if (scaled != bitmap)
+ bitmap.Dispose();
+ return scaled;
+ }
+
+ static ABitmap ScaleBitmap(ABitmap source, int targetWidth, int targetHeight)
+ {
+ int width = source.Width;
+ int height = source.Height;
+
+ float widthRatio = (float)targetWidth / width;
+ float heightRatio = (float)targetHeight / height;
+ float ratio = Math.Min(widthRatio, heightRatio);
+
+ int newWidth = (int)(width * ratio);
+ int newHeight = (int)(height * ratio);
+
+ return ABitmap.CreateScaledBitmap(source, newWidth, newHeight, true)!;
+ }
+
protected IMapPin? GetPinForMarker(Marker marker)
{
IMapPin? targetPin = null;
diff --git a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Android.cs b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Android.cs
index b02d5020e563..f79a3dac4476 100644
--- a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Android.cs
+++ b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Android.cs
@@ -1,5 +1,4 @@
-using Android.Gms.Maps;
-using Android.Gms.Maps.Model;
+using Android.Gms.Maps.Model;
using Microsoft.Maui.Handlers;
namespace Microsoft.Maui.Maps.Handlers
@@ -23,5 +22,12 @@ public static void MapAddress(IMapPinHandler handler, IMapPin mapPin)
{
handler.PlatformView.SetSnippet(mapPin.Address);
}
+
+ // Note: ImageSource is handled in MapHandler.AddPinAsync
+ // because the icon must be set on MarkerOptions BEFORE calling Map.AddMarker()
+ public static void MapImageSource(IMapPinHandler handler, IMapPin mapPin)
+ {
+ // No-op: Image is applied when the marker is created in MapHandler.AddPinAsync
+ }
}
}
diff --git a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Standard.cs b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Standard.cs
index 08e42e194907..d91385959e81 100644
--- a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Standard.cs
+++ b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Standard.cs
@@ -9,5 +9,7 @@ public static void MapLocation(IMapPinHandler handler, IMapPin mapPin) { }
public static void MapLabel(IMapPinHandler handler, IMapPin mapPin) { }
public static void MapAddress(IMapPinHandler handler, IMapPin mapPin) { }
+
+ public static void MapImageSource(IMapPinHandler handler, IMapPin mapPin) { }
}
}
diff --git a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Tizen.cs b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Tizen.cs
index 08e42e194907..d91385959e81 100644
--- a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Tizen.cs
+++ b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Tizen.cs
@@ -9,5 +9,7 @@ public static void MapLocation(IMapPinHandler handler, IMapPin mapPin) { }
public static void MapLabel(IMapPinHandler handler, IMapPin mapPin) { }
public static void MapAddress(IMapPinHandler handler, IMapPin mapPin) { }
+
+ public static void MapImageSource(IMapPinHandler handler, IMapPin mapPin) { }
}
}
diff --git a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Windows.cs b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Windows.cs
index 37ac75d1300f..d42877995395 100644
--- a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Windows.cs
+++ b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Windows.cs
@@ -11,5 +11,7 @@ public static void MapLocation(IMapPinHandler handler, IMapPin mapPin) { }
public static void MapLabel(IMapPinHandler handler, IMapPin mapPin) { }
public static void MapAddress(IMapPinHandler handler, IMapPin mapPin) { }
+
+ public static void MapImageSource(IMapPinHandler handler, IMapPin mapPin) { }
}
}
diff --git a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.cs b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.cs
index dcc406e26895..a5f5e245195a 100644
--- a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.cs
+++ b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.cs
@@ -26,6 +26,7 @@ public partial class MapPinHandler : IMapPinHandler
[nameof(IMapPin.Location)] = MapLocation,
[nameof(IMapPin.Label)] = MapLabel,
[nameof(IMapPin.Address)] = MapAddress,
+ [nameof(IMapPin.ImageSource)] = MapImageSource,
};
///
diff --git a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.iOS.cs b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.iOS.cs
index 75e134c11f8e..92feb8ba6184 100644
--- a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.iOS.cs
+++ b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.iOS.cs
@@ -26,5 +26,12 @@ public static void MapAddress(IMapPinHandler handler, IMapPin mapPin)
if (handler.PlatformView is MKPointAnnotation mKPointAnnotation)
mKPointAnnotation.Subtitle = mapPin.Address;
}
+
+ // Note: ImageSource is handled in MauiMKMapView.GetViewForAnnotation
+ // because the image is set on the MKAnnotationView, not on the IMKAnnotation
+ public static void MapImageSource(IMapPinHandler handler, IMapPin mapPin)
+ {
+ // No-op: Image is applied when the annotation view is created in GetViewForAnnotation
+ }
}
}
diff --git a/src/Core/maps/src/Platform/iOS/MauiMKMapView.cs b/src/Core/maps/src/Platform/iOS/MauiMKMapView.cs
index 09804cd12f93..c827ce9604e9 100644
--- a/src/Core/maps/src/Platform/iOS/MauiMKMapView.cs
+++ b/src/Core/maps/src/Platform/iOS/MauiMKMapView.cs
@@ -4,6 +4,8 @@
using System.Linq;
using CoreLocation;
using MapKit;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
using Microsoft.Maui.Maps.Handlers;
using Microsoft.Maui.Platform;
using ObjCRuntime;
@@ -102,21 +104,34 @@ MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotatio
const string defaultPinId = "defaultPin";
mapPin = mapView.DequeueReusableAnnotation(defaultPinId);
+
+ // Find the IMapPin associated with this annotation
+ IMapPin? pin = GetPinForAnnotation(annotation);
+
+ // Determine if we need a custom image view or the default marker view
+ bool hasCustomImage = pin?.ImageSource != null;
+ string reuseId = hasCustomImage ? "customPin" : "defaultPin";
+
+ mapPin = mapView.DequeueReusableAnnotation(reuseId);
if (mapPin == null)
{
- if (OperatingSystem.IsIOSVersionAtLeast(11))
+ if (hasCustomImage)
+ {
+ // Use MKAnnotationView for custom images
+ mapPin = new MKAnnotationView(annotation, reuseId);
+ }
+ else if (OperatingSystem.IsIOSVersionAtLeast(11))
{
- mapPin = new MKMarkerAnnotationView(annotation, defaultPinId);
+ mapPin = new MKMarkerAnnotationView(annotation, reuseId);
}
else
{
- mapPin = new MKPinAnnotationView(annotation, defaultPinId);
-
+ mapPin = new MKPinAnnotationView(annotation, reuseId);
}
mapPin.CanShowCallout = true;
- if (OperatingSystem.IsIOSVersionAtLeast(11))
+ if (!hasCustomImage && OperatingSystem.IsIOSVersionAtLeast(11))
{
// Need to set this to get the callout bubble to show up
// Without this no callout is shown, it's displayed differently
@@ -129,8 +144,6 @@ MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotatio
// Set clustering identifier if clustering is enabled
if (_isClusteringEnabled && OperatingSystem.IsIOSVersionAtLeast(11))
{
- // Get the clustering identifier from the pin
- var pin = GetPinForAnnotation(annotation);
if (pin != null)
{
mapPin.ClusteringIdentifier = pin.ClusteringIdentifier;
@@ -143,7 +156,15 @@ MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotatio
// re-applied from GetPinForAnnotation when clustering is re-enabled.
mapPin.ClusteringIdentifier = null;
}
-
+
+ // Apply custom image if present
+ if (hasCustomImage && pin?.ImageSource != null)
+ {
+ // Clear any existing image on a reused annotation view before loading the new one
+ mapPin.Image = null;
+ ApplyCustomImageAsync(mapPin, pin).FireAndForget();
+ }
+
AttachGestureToPin(mapPin, annotation);
return mapPin;
@@ -224,6 +245,57 @@ void ZoomToShowClusterPins(IMKAnnotation[] annotations)
SetVisibleMapRect(paddedRect, true);
}
+ async System.Threading.Tasks.Task ApplyCustomImageAsync(MKAnnotationView annotationView, IMapPin pin)
+ {
+ _handlerRef.TryGetTarget(out IMapHandler? handler);
+ if (handler?.MauiContext == null || pin.ImageSource == null)
+ return;
+
+ // Capture the annotation before the async operation to detect reuse
+ var targetAnnotation = annotationView.Annotation;
+
+ try
+ {
+ var result = await pin.ImageSource.GetPlatformImageAsync(handler.MauiContext);
+
+ // Verify the annotation view hasn't been reused for a different pin
+ if (annotationView.Annotation != targetAnnotation)
+ return;
+
+ if (result?.Value is UIImage image)
+ {
+ // Scale image to appropriate pin size (32x32 points)
+ var scaledImage = ScaleImage(image, new CoreGraphics.CGSize(32, 32));
+ annotationView.Image = scaledImage;
+ }
+ }
+ catch (Exception ex)
+ {
+ if (_handlerRef.TryGetTarget(out var currentHandler))
+ {
+ var logger = currentHandler.MauiContext?.Services?.GetService>();
+ logger?.LogWarning(ex, "Failed to load custom pin icon");
+ }
+ }
+ }
+
+ static UIImage ScaleImage(UIImage image, CoreGraphics.CGSize targetSize)
+ {
+ var size = image.Size;
+ var widthRatio = targetSize.Width / size.Width;
+ var heightRatio = targetSize.Height / size.Height;
+ var ratio = (nfloat)Math.Min(widthRatio, heightRatio);
+
+ var newSize = new CoreGraphics.CGSize(size.Width * ratio, size.Height * ratio);
+
+ UIGraphics.BeginImageContextWithOptions(newSize, false, image.CurrentScale);
+ image.Draw(new CoreGraphics.CGRect(0, 0, newSize.Width, newSize.Height));
+ var scaledImage = UIGraphics.GetImageFromCurrentImageContext();
+ UIGraphics.EndImageContext();
+
+ return scaledImage ?? image;
+ }
+
internal void AddPins(IList pins)
{
_handlerRef.TryGetTarget(out IMapHandler? handler);
diff --git a/src/Core/maps/src/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Core/maps/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
index ca3a9deaff76..618f7d226d94 100644
--- a/src/Core/maps/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
+++ b/src/Core/maps/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
@@ -6,6 +6,7 @@ Microsoft.Maui.Maps.IMapElement.Clicked() -> void
Microsoft.Maui.Maps.IMapElement.IsVisible.get -> bool
Microsoft.Maui.Maps.IMapElement.ZIndex.get -> int
Microsoft.Maui.Maps.IMapPin.ClusteringIdentifier.get -> string!
+Microsoft.Maui.Maps.IMapPin.ImageSource.get -> Microsoft.Maui.IImageSource?
Microsoft.Maui.Maps.MapSpanTypeConverter
Microsoft.Maui.Maps.MapSpanTypeConverter.MapSpanTypeConverter() -> void
override Microsoft.Maui.Maps.MapSpanTypeConverter.CanConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Type! sourceType) -> bool
@@ -15,3 +16,4 @@ override Microsoft.Maui.Maps.MapSpanTypeConverter.ConvertTo(System.ComponentMode
static Microsoft.Maui.Maps.Handlers.MapElementHandler.MapIsVisible(Microsoft.Maui.Maps.Handlers.IMapElementHandler! handler, Microsoft.Maui.Maps.IMapElement! mapElement) -> void
static Microsoft.Maui.Maps.Handlers.MapElementHandler.MapZIndex(Microsoft.Maui.Maps.Handlers.IMapElementHandler! handler, Microsoft.Maui.Maps.IMapElement! mapElement) -> void
static Microsoft.Maui.Maps.Handlers.MapHandler.MapIsClusteringEnabled(Microsoft.Maui.Maps.Handlers.IMapHandler! handler, Microsoft.Maui.Maps.IMap! map) -> void
+static Microsoft.Maui.Maps.Handlers.MapPinHandler.MapImageSource(Microsoft.Maui.Maps.Handlers.IMapPinHandler! handler, Microsoft.Maui.Maps.IMapPin! mapPin) -> void
diff --git a/src/Core/maps/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Core/maps/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
index a2d9f131ee39..c41cd2ed787e 100644
--- a/src/Core/maps/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
+++ b/src/Core/maps/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
@@ -6,6 +6,7 @@ Microsoft.Maui.Maps.IMapElement.Clicked() -> void
Microsoft.Maui.Maps.IMapElement.IsVisible.get -> bool
Microsoft.Maui.Maps.IMapElement.ZIndex.get -> int
Microsoft.Maui.Maps.IMapPin.ClusteringIdentifier.get -> string!
+Microsoft.Maui.Maps.IMapPin.ImageSource.get -> Microsoft.Maui.IImageSource?
Microsoft.Maui.Maps.MapSpanTypeConverter
Microsoft.Maui.Maps.MapSpanTypeConverter.MapSpanTypeConverter() -> void
Microsoft.Maui.Maps.Platform.MauiMKMapView.IsClusteringEnabled.get -> bool
@@ -17,3 +18,4 @@ override Microsoft.Maui.Maps.MapSpanTypeConverter.ConvertTo(System.ComponentMode
static Microsoft.Maui.Maps.Handlers.MapElementHandler.MapIsVisible(Microsoft.Maui.Maps.Handlers.IMapElementHandler! handler, Microsoft.Maui.Maps.IMapElement! mapElement) -> void
static Microsoft.Maui.Maps.Handlers.MapElementHandler.MapZIndex(Microsoft.Maui.Maps.Handlers.IMapElementHandler! handler, Microsoft.Maui.Maps.IMapElement! mapElement) -> void
static Microsoft.Maui.Maps.Handlers.MapHandler.MapIsClusteringEnabled(Microsoft.Maui.Maps.Handlers.IMapHandler! handler, Microsoft.Maui.Maps.IMap! map) -> void
+static Microsoft.Maui.Maps.Handlers.MapPinHandler.MapImageSource(Microsoft.Maui.Maps.Handlers.IMapPinHandler! handler, Microsoft.Maui.Maps.IMapPin! mapPin) -> void
diff --git a/src/Core/maps/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Core/maps/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
index a2d9f131ee39..c41cd2ed787e 100644
--- a/src/Core/maps/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
+++ b/src/Core/maps/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
@@ -6,6 +6,7 @@ Microsoft.Maui.Maps.IMapElement.Clicked() -> void
Microsoft.Maui.Maps.IMapElement.IsVisible.get -> bool
Microsoft.Maui.Maps.IMapElement.ZIndex.get -> int
Microsoft.Maui.Maps.IMapPin.ClusteringIdentifier.get -> string!
+Microsoft.Maui.Maps.IMapPin.ImageSource.get -> Microsoft.Maui.IImageSource?
Microsoft.Maui.Maps.MapSpanTypeConverter
Microsoft.Maui.Maps.MapSpanTypeConverter.MapSpanTypeConverter() -> void
Microsoft.Maui.Maps.Platform.MauiMKMapView.IsClusteringEnabled.get -> bool
@@ -17,3 +18,4 @@ override Microsoft.Maui.Maps.MapSpanTypeConverter.ConvertTo(System.ComponentMode
static Microsoft.Maui.Maps.Handlers.MapElementHandler.MapIsVisible(Microsoft.Maui.Maps.Handlers.IMapElementHandler! handler, Microsoft.Maui.Maps.IMapElement! mapElement) -> void
static Microsoft.Maui.Maps.Handlers.MapElementHandler.MapZIndex(Microsoft.Maui.Maps.Handlers.IMapElementHandler! handler, Microsoft.Maui.Maps.IMapElement! mapElement) -> void
static Microsoft.Maui.Maps.Handlers.MapHandler.MapIsClusteringEnabled(Microsoft.Maui.Maps.Handlers.IMapHandler! handler, Microsoft.Maui.Maps.IMap! map) -> void
+static Microsoft.Maui.Maps.Handlers.MapPinHandler.MapImageSource(Microsoft.Maui.Maps.Handlers.IMapPinHandler! handler, Microsoft.Maui.Maps.IMapPin! mapPin) -> void
diff --git a/src/Core/maps/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt b/src/Core/maps/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
index ca3a9deaff76..618f7d226d94 100644
--- a/src/Core/maps/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
+++ b/src/Core/maps/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
@@ -6,6 +6,7 @@ Microsoft.Maui.Maps.IMapElement.Clicked() -> void
Microsoft.Maui.Maps.IMapElement.IsVisible.get -> bool
Microsoft.Maui.Maps.IMapElement.ZIndex.get -> int
Microsoft.Maui.Maps.IMapPin.ClusteringIdentifier.get -> string!
+Microsoft.Maui.Maps.IMapPin.ImageSource.get -> Microsoft.Maui.IImageSource?
Microsoft.Maui.Maps.MapSpanTypeConverter
Microsoft.Maui.Maps.MapSpanTypeConverter.MapSpanTypeConverter() -> void
override Microsoft.Maui.Maps.MapSpanTypeConverter.CanConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Type! sourceType) -> bool
@@ -15,3 +16,4 @@ override Microsoft.Maui.Maps.MapSpanTypeConverter.ConvertTo(System.ComponentMode
static Microsoft.Maui.Maps.Handlers.MapElementHandler.MapIsVisible(Microsoft.Maui.Maps.Handlers.IMapElementHandler! handler, Microsoft.Maui.Maps.IMapElement! mapElement) -> void
static Microsoft.Maui.Maps.Handlers.MapElementHandler.MapZIndex(Microsoft.Maui.Maps.Handlers.IMapElementHandler! handler, Microsoft.Maui.Maps.IMapElement! mapElement) -> void
static Microsoft.Maui.Maps.Handlers.MapHandler.MapIsClusteringEnabled(Microsoft.Maui.Maps.Handlers.IMapHandler! handler, Microsoft.Maui.Maps.IMap! map) -> void
+static Microsoft.Maui.Maps.Handlers.MapPinHandler.MapImageSource(Microsoft.Maui.Maps.Handlers.IMapPinHandler! handler, Microsoft.Maui.Maps.IMapPin! mapPin) -> void
diff --git a/src/Core/maps/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Core/maps/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
index ca3a9deaff76..618f7d226d94 100644
--- a/src/Core/maps/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
+++ b/src/Core/maps/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
@@ -6,6 +6,7 @@ Microsoft.Maui.Maps.IMapElement.Clicked() -> void
Microsoft.Maui.Maps.IMapElement.IsVisible.get -> bool
Microsoft.Maui.Maps.IMapElement.ZIndex.get -> int
Microsoft.Maui.Maps.IMapPin.ClusteringIdentifier.get -> string!
+Microsoft.Maui.Maps.IMapPin.ImageSource.get -> Microsoft.Maui.IImageSource?
Microsoft.Maui.Maps.MapSpanTypeConverter
Microsoft.Maui.Maps.MapSpanTypeConverter.MapSpanTypeConverter() -> void
override Microsoft.Maui.Maps.MapSpanTypeConverter.CanConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Type! sourceType) -> bool
@@ -15,3 +16,4 @@ override Microsoft.Maui.Maps.MapSpanTypeConverter.ConvertTo(System.ComponentMode
static Microsoft.Maui.Maps.Handlers.MapElementHandler.MapIsVisible(Microsoft.Maui.Maps.Handlers.IMapElementHandler! handler, Microsoft.Maui.Maps.IMapElement! mapElement) -> void
static Microsoft.Maui.Maps.Handlers.MapElementHandler.MapZIndex(Microsoft.Maui.Maps.Handlers.IMapElementHandler! handler, Microsoft.Maui.Maps.IMapElement! mapElement) -> void
static Microsoft.Maui.Maps.Handlers.MapHandler.MapIsClusteringEnabled(Microsoft.Maui.Maps.Handlers.IMapHandler! handler, Microsoft.Maui.Maps.IMap! map) -> void
+static Microsoft.Maui.Maps.Handlers.MapPinHandler.MapImageSource(Microsoft.Maui.Maps.Handlers.IMapPinHandler! handler, Microsoft.Maui.Maps.IMapPin! mapPin) -> void
diff --git a/src/Core/maps/src/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Core/maps/src/PublicAPI/net/PublicAPI.Unshipped.txt
index ca3a9deaff76..618f7d226d94 100644
--- a/src/Core/maps/src/PublicAPI/net/PublicAPI.Unshipped.txt
+++ b/src/Core/maps/src/PublicAPI/net/PublicAPI.Unshipped.txt
@@ -6,6 +6,7 @@ Microsoft.Maui.Maps.IMapElement.Clicked() -> void
Microsoft.Maui.Maps.IMapElement.IsVisible.get -> bool
Microsoft.Maui.Maps.IMapElement.ZIndex.get -> int
Microsoft.Maui.Maps.IMapPin.ClusteringIdentifier.get -> string!
+Microsoft.Maui.Maps.IMapPin.ImageSource.get -> Microsoft.Maui.IImageSource?
Microsoft.Maui.Maps.MapSpanTypeConverter
Microsoft.Maui.Maps.MapSpanTypeConverter.MapSpanTypeConverter() -> void
override Microsoft.Maui.Maps.MapSpanTypeConverter.CanConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Type! sourceType) -> bool
@@ -15,3 +16,4 @@ override Microsoft.Maui.Maps.MapSpanTypeConverter.ConvertTo(System.ComponentMode
static Microsoft.Maui.Maps.Handlers.MapElementHandler.MapIsVisible(Microsoft.Maui.Maps.Handlers.IMapElementHandler! handler, Microsoft.Maui.Maps.IMapElement! mapElement) -> void
static Microsoft.Maui.Maps.Handlers.MapElementHandler.MapZIndex(Microsoft.Maui.Maps.Handlers.IMapElementHandler! handler, Microsoft.Maui.Maps.IMapElement! mapElement) -> void
static Microsoft.Maui.Maps.Handlers.MapHandler.MapIsClusteringEnabled(Microsoft.Maui.Maps.Handlers.IMapHandler! handler, Microsoft.Maui.Maps.IMap! map) -> void
+static Microsoft.Maui.Maps.Handlers.MapPinHandler.MapImageSource(Microsoft.Maui.Maps.Handlers.IMapPinHandler! handler, Microsoft.Maui.Maps.IMapPin! mapPin) -> void
diff --git a/src/Core/maps/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt b/src/Core/maps/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt
index ca3a9deaff76..618f7d226d94 100644
--- a/src/Core/maps/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt
+++ b/src/Core/maps/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt
@@ -6,6 +6,7 @@ Microsoft.Maui.Maps.IMapElement.Clicked() -> void
Microsoft.Maui.Maps.IMapElement.IsVisible.get -> bool
Microsoft.Maui.Maps.IMapElement.ZIndex.get -> int
Microsoft.Maui.Maps.IMapPin.ClusteringIdentifier.get -> string!
+Microsoft.Maui.Maps.IMapPin.ImageSource.get -> Microsoft.Maui.IImageSource?
Microsoft.Maui.Maps.MapSpanTypeConverter
Microsoft.Maui.Maps.MapSpanTypeConverter.MapSpanTypeConverter() -> void
override Microsoft.Maui.Maps.MapSpanTypeConverter.CanConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Type! sourceType) -> bool
@@ -15,3 +16,4 @@ override Microsoft.Maui.Maps.MapSpanTypeConverter.ConvertTo(System.ComponentMode
static Microsoft.Maui.Maps.Handlers.MapElementHandler.MapIsVisible(Microsoft.Maui.Maps.Handlers.IMapElementHandler! handler, Microsoft.Maui.Maps.IMapElement! mapElement) -> void
static Microsoft.Maui.Maps.Handlers.MapElementHandler.MapZIndex(Microsoft.Maui.Maps.Handlers.IMapElementHandler! handler, Microsoft.Maui.Maps.IMapElement! mapElement) -> void
static Microsoft.Maui.Maps.Handlers.MapHandler.MapIsClusteringEnabled(Microsoft.Maui.Maps.Handlers.IMapHandler! handler, Microsoft.Maui.Maps.IMap! map) -> void
+static Microsoft.Maui.Maps.Handlers.MapPinHandler.MapImageSource(Microsoft.Maui.Maps.Handlers.IMapPinHandler! handler, Microsoft.Maui.Maps.IMapPin! mapPin) -> void