diff --git a/src/Controls/Maps/src/AppHostBuilderExtensions.cs b/src/Controls/Maps/src/AppHostBuilderExtensions.cs index 31dfcc262545..0facb94489a8 100644 --- a/src/Controls/Maps/src/AppHostBuilderExtensions.cs +++ b/src/Controls/Maps/src/AppHostBuilderExtensions.cs @@ -22,7 +22,37 @@ public static partial class AppHostBuilderExtensions /// /// The to configure. /// The configured . - /// Thrown on Windows because the maps control currently is not implemented for Windows. + /// + /// + /// Windows (Azure Maps): Set your Azure Maps subscription key using ConfigureEssentials: + /// + /// builder.ConfigureEssentials(essentials => essentials.UseMapServiceToken("YOUR_AZURE_MAPS_KEY")); + /// + /// Get a key from the Azure Portal: https://portal.azure.com → Azure Maps account → Authentication + /// + /// + /// Windows Features (via Azure Maps JS API): + /// The Windows implementation uses the WinUI 3 MapControl backed by Azure Maps. The following features are + /// implemented by accessing the Azure Maps JavaScript API through the control's internal WebView2: + /// + /// MoveToRegion: Navigates via map.setCamera(). + /// MapType: Street/Satellite/Hybrid via map.setStyle(). + /// IsTrafficEnabled: Traffic flow and incidents via map.setTraffic(). + /// IsScrollEnabled/IsZoomEnabled: Independent control via map.setUserInteraction(). + /// Pins: Via MapIcon on a MapElementsLayer. + /// + /// + /// + /// Windows Platform Limitations: + /// + /// User Location: Not built-in; requires manual Geolocation API integration. + /// Shapes: Polylines, polygons, and circles are not supported (MapElementsLayer only supports MapIcon). + /// Pin Labels: MapIcon does not support labels or info windows. + /// Map.Clicked (background): Only MapElement clicks fire events, not empty map area clicks. + /// + /// See documentation for detailed platform information. + /// + /// public static MauiAppBuilder UseMauiMaps(this MauiAppBuilder builder) { builder @@ -63,20 +93,13 @@ public static MauiAppBuilder UseMauiMaps(this MauiAppBuilder builder) /// /// An instance of on which to register the map handlers. /// The provided object with the registered map handlers for subsequent registration calls. - /// Thrown on Windows because the maps control currently is not implemented for Windows. public static IMauiHandlersCollection AddMauiMaps(this IMauiHandlersCollection handlersCollection) { -#if __ANDROID__ || __IOS__ handlersCollection.AddHandler(); handlersCollection.AddHandler(); handlersCollection.AddHandler(); -#endif -#if WINDOWS - throw new NotImplementedException(".NET MAUI Maps is currently not implemented for Windows. For more information, please see: https://aka.ms/maui-maps-no-windows"); -#else return handlersCollection; -#endif } } } diff --git a/src/Core/maps/src/Handlers/Map/MapHandler.Windows.cs b/src/Core/maps/src/Handlers/Map/MapHandler.Windows.cs index 4a776d8603b0..0c473639f512 100644 --- a/src/Core/maps/src/Handlers/Map/MapHandler.Windows.cs +++ b/src/Core/maps/src/Handlers/Map/MapHandler.Windows.cs @@ -1,30 +1,460 @@ using System; +using System.Collections.Generic; +using System.Globalization; +using Microsoft.Maui.Devices.Sensors; using Microsoft.Maui.Handlers; using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; +using Windows.Devices.Geolocation; namespace Microsoft.Maui.Maps.Handlers { + // TODO: For .NET 11, refactor setup/cleanup into ConnectHandler/DisconnectHandler overrides + // to match the iOS/Android handler pattern. Avoided for now to prevent new PublicAPI entries. + /// + /// Handler for the Map control on Windows using the WinUI 3 MapControl backed by Azure Maps. + /// + /// + /// + /// Authentication: Set your Azure Maps subscription key using: + /// builder.ConfigureEssentials(e => e.UseMapServiceToken("YOUR_AZURE_MAPS_KEY")); + /// Get a key from the Azure Portal: https://portal.azure.com → Azure Maps account → Authentication. + /// + /// + /// Supported features (via Azure Maps JS API through internal WebView2): + /// + /// MoveToRegion: Navigates via map.setCamera(). + /// MapType: Street/Satellite/Hybrid via map.setStyle() (road/satellite/satellite_road_labels). + /// IsTrafficEnabled: Traffic flow and incidents via map.setTraffic(). + /// IsZoomEnabled/IsScrollEnabled: Independent control via map.setUserInteraction(). + /// Pins: Displays map pins using on a . Pin click events are supported. + /// + /// + /// + /// Unsupported features (no-op on Windows): + /// + /// IsShowingUser: Not built-in. Use the Geolocation API and a custom to display user location. + /// Polylines/Polygons/Circles: only supports . Shapes are not rendered. + /// Pin Labels/InfoWindows: does not support labels or info windows. + /// Map.Clicked (background): The event only fires for clicks, not empty map area clicks. + /// + /// + /// public partial class MapHandler : ViewHandler { + MapControl? _mapControl; + WebView2? _webView; + bool _webViewReady; + MapElementsLayer? _pinsLayer; + MapElementsLayer? _mapElementsLayer; + readonly List _mapIcons = new(); - protected override FrameworkElement CreatePlatformView() => throw new NotImplementedException(); + /// + protected override FrameworkElement CreatePlatformView() + { + _mapControl = new MapControl(); - public static void MapMapType(IMapHandler handler, IMap map) => throw new NotImplementedException(); + var token = ApplicationModel.Platform.MapServiceToken; - public static void MapIsZoomEnabled(IMapHandler handler, IMap map) => throw new NotImplementedException(); + if (!string.IsNullOrEmpty(token)) + { + _mapControl.MapServiceToken = token; + } - public static void MapIsScrollEnabled(IMapHandler handler, IMap map) => throw new NotImplementedException(); + _mapControl.ZoomLevel = 2; + _mapControl.InteractiveControlsVisible = true; - public static void MapIsTrafficEnabled(IMapHandler handler, IMap map) => throw new NotImplementedException(); + _mapControl.Loaded += OnMapControlLoaded; + _mapControl.Unloaded += OnMapControlUnloaded; - public static void MapIsShowingUser(IMapHandler handler, IMap map) => throw new NotImplementedException(); + _pinsLayer = new MapElementsLayer(); + _pinsLayer.MapElementClick += OnPinLayerElementClick; + _mapControl.Layers.Add(_pinsLayer); - public static void MapMoveToRegion(IMapHandler handler, IMap map, object? arg) => throw new NotImplementedException(); + _mapElementsLayer = new MapElementsLayer(); + _mapControl.Layers.Add(_mapElementsLayer); - public static void MapPins(IMapHandler handler, IMap map) => throw new NotImplementedException(); + return _mapControl; + } - public static void MapElements(IMapHandler handler, IMap map) => throw new NotImplementedException(); + void OnMapControlLoaded(object sender, RoutedEventArgs e) + { + if (_mapControl == null) + return; - public void UpdateMapElement(IMapElement element) => throw new NotImplementedException(); + _mapControl.Loaded -= OnMapControlLoaded; + + if (!TryDiscoverWebView()) + { + // WebView2 child may not be available yet during complex initialization. + // Retry on LayoutUpdated until found. + _mapControl.LayoutUpdated += OnMapControlLayoutUpdated; + } + } + + void OnMapControlLayoutUpdated(object? sender, object e) + { + if (TryDiscoverWebView() && _mapControl != null) + { + _mapControl.LayoutUpdated -= OnMapControlLayoutUpdated; + } + } + + bool TryDiscoverWebView() + { + if (_mapControl == null || _webView != null) + return true; + + if (VisualTreeHelper.GetChildrenCount(_mapControl) > 0 && + VisualTreeHelper.GetChild(_mapControl, 0) is WebView2 webView) + { + _webView = webView; + _webView.NavigationCompleted += OnWebViewNavigationCompleted; + return true; + } + + return false; + } + + void OnWebViewNavigationCompleted(WebView2 sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationCompletedEventArgs args) + { + sender.NavigationCompleted -= OnWebViewNavigationCompleted; + _webViewReady = true; + + // Apply any pending state that was queued before the WebView was ready + if (_pendingSpan != null) + { + var span = _pendingSpan; + _pendingSpan = null; + _ = ExecuteJsAsync(string.Format( + CultureInfo.InvariantCulture, + "map.setCamera({{ center: [{0}, {1}], zoom: {2}, type: 'ease', duration: 300 }});", + span.Center.Longitude, span.Center.Latitude, CalculateZoom(span))); + } + + // Apply initial property state via JS now that the map is ready + if (VirtualView != null) + { + _ = ApplyMapTypeAsync(VirtualView.MapType); + _ = ApplyTrafficAsync(VirtualView.IsTrafficEnabled); + _ = ApplyUserInteractionAsync(VirtualView.IsScrollEnabled, VirtualView.IsZoomEnabled); + } + } + + MapSpan? _pendingSpan; + + /// + /// Executes a JavaScript command on the Azure Maps instance inside the WebView2. + /// + async System.Threading.Tasks.Task ExecuteJsAsync(string script) + { + if (_webView == null || !_webViewReady) + return; + + try + { + await _webView.ExecuteScriptAsync(script); + } + catch (InvalidOperationException) + { + // Expected: WebView2 may not be fully initialized or was disposed + } + catch (Exception ex) + { + System.Diagnostics.Trace.WriteLine($"[MapHandler] JS execution failed: {ex.Message}"); + } + } + + /// + /// Applies the map style corresponding to the MAUI via the Azure Maps JS API. + /// + System.Threading.Tasks.Task ApplyMapTypeAsync(MapType mapType) + { + // Azure Maps style names: https://learn.microsoft.com/azure/azure-maps/supported-map-styles + var style = mapType switch + { + MapType.Street => "road", + MapType.Satellite => "satellite", + MapType.Hybrid => "satellite_road_labels", + _ => "road" + }; + return ExecuteJsAsync($"map.setStyle({{ style: '{style}' }});"); + } + + /// + /// Enables or disables the traffic overlay via the Azure Maps JS API. + /// + System.Threading.Tasks.Task ApplyTrafficAsync(bool enabled) + { + if (enabled) + return ExecuteJsAsync("map.setTraffic({ flow: 'relative', incidents: true });"); + else + return ExecuteJsAsync("map.setTraffic({ flow: 'none', incidents: false });"); + } + + /// + /// Configures independent scroll and zoom interaction via the Azure Maps JS API. + /// + System.Threading.Tasks.Task ApplyUserInteractionAsync(bool scrollEnabled, bool zoomEnabled) + { + var drag = scrollEnabled ? "true" : "false"; + var scroll = zoomEnabled ? "true" : "false"; + var dblClick = zoomEnabled ? "true" : "false"; + return ExecuteJsAsync($"map.setUserInteraction({{ dragPanInteraction: {drag}, scrollZoomInteraction: {scroll}, dblClickZoomInteraction: {dblClick} }});"); + } + + static double CalculateZoom(MapSpan span) + { + double zoomLat = Math.Log2(360.0 / span.LatitudeDegrees); + double zoomLon = Math.Log2(360.0 / span.LongitudeDegrees); + return Math.Clamp(Math.Min(zoomLat, zoomLon), 0, 24); + } + + void OnMapControlUnloaded(object sender, RoutedEventArgs e) + { + if (_mapControl != null) + { + _mapControl.Loaded -= OnMapControlLoaded; + _mapControl.LayoutUpdated -= OnMapControlLayoutUpdated; + _mapControl.Unloaded -= OnMapControlUnloaded; + + if (_pinsLayer != null) + { + _pinsLayer.MapElementClick -= OnPinLayerElementClick; + _mapControl.Layers.Remove(_pinsLayer); + _pinsLayer = null; + } + + if (_mapElementsLayer != null) + { + _mapControl.Layers.Remove(_mapElementsLayer); + _mapElementsLayer = null; + } + } + + _mapIcons.Clear(); + _pendingSpan = null; + + if (_webView != null) + { + _webView.NavigationCompleted -= OnWebViewNavigationCompleted; + } + + _webView = null; + _webViewReady = false; + } + + void OnPinLayerElementClick(MapElementsLayer sender, MapElementClickEventArgs args) + { + if (args.Element is MapIcon clickedIcon) + { + var pin = GetPinForMapIcon(clickedIcon); + if (pin != null) + { + pin.SendMarkerClick(); + return; // Pin click should not also fire map click (matches iOS/Android behavior) + } + } + + VirtualView?.Clicked(new Location(args.Location.Position.Latitude, args.Location.Position.Longitude)); + } + + IMapPin? GetPinForMapIcon(MapIcon mapIcon) + { + if (VirtualView == null) + return null; + + for (int i = 0; i < VirtualView.Pins.Count; i++) + { + if (ReferenceEquals(VirtualView.Pins[i].MarkerId, mapIcon)) + return VirtualView.Pins[i]; + } + return null; + } + + /// + /// Maps the property via the Azure Maps JS map.setStyle() API. + /// + /// + /// Maps MAUI to road, to satellite, + /// and to satellite_road_labels. + /// + public static void MapMapType(IMapHandler handler, IMap map) + { + if (handler is MapHandler mapHandler && mapHandler._webViewReady) + { + _ = mapHandler.ApplyMapTypeAsync(map.MapType); + } + } + + /// + /// Maps via the Azure Maps JS map.setUserInteraction() API. + /// + /// + /// Controls scrollZoomInteraction and dblClickZoomInteraction independently from scroll/drag. + /// Also keeps InteractiveControlsVisible in sync so the built-in UI controls remain accessible. + /// + public static void MapIsZoomEnabled(IMapHandler handler, IMap map) + { + if (handler is MapHandler mapHandler && mapHandler._mapControl != null) + { + mapHandler._mapControl.InteractiveControlsVisible = map.IsZoomEnabled || map.IsScrollEnabled; + + if (mapHandler._webViewReady) + { + _ = mapHandler.ApplyUserInteractionAsync(map.IsScrollEnabled, map.IsZoomEnabled); + } + } + } + + /// + /// Maps via the Azure Maps JS map.setUserInteraction() API. + /// + /// + /// Controls dragPanInteraction independently from zoom. + /// Also keeps InteractiveControlsVisible in sync so the built-in UI controls remain accessible. + /// + public static void MapIsScrollEnabled(IMapHandler handler, IMap map) + { + if (handler is MapHandler mapHandler && mapHandler._mapControl != null) + { + mapHandler._mapControl.InteractiveControlsVisible = map.IsZoomEnabled || map.IsScrollEnabled; + + if (mapHandler._webViewReady) + { + _ = mapHandler.ApplyUserInteractionAsync(map.IsScrollEnabled, map.IsZoomEnabled); + } + } + } + + /// + /// Maps via the Azure Maps JS map.setTraffic() API. + /// + /// + /// When enabled, shows traffic flow (color-coded roads) and incident icons. + /// When disabled, removes both traffic flow and incident overlays. + /// + public static void MapIsTrafficEnabled(IMapHandler handler, IMap map) + { + if (handler is MapHandler mapHandler && mapHandler._webViewReady) + { + _ = mapHandler.ApplyTrafficAsync(map.IsTrafficEnabled); + } + } + + /// + /// Maps . No-op on Windows: the WinUI 3 MapControl has no built-in user location display. + /// + public static void MapIsShowingUser(IMapHandler handler, IMap map) + { + // No-op: user location requires Geolocation API + custom MapIcon. + } + + /// + /// Handles the command by navigating via the Azure Maps JS camera API. + /// + /// + /// The WinUI 3 MapControl wraps Azure Maps in a WebView2. Setting the Center dependency property + /// does not reliably navigate the map view. Instead, we call map.setCamera() via JavaScript. + /// The zoom level is calculated from the using the Spherical Mercator formula: + /// zoom = log2(360 / degrees), clamped to the Azure Maps range of 0–24. + /// Navigation uses an ease animation (300ms) for smooth transitions. + /// + public static void MapMoveToRegion(IMapHandler handler, IMap map, object? arg) + { + if (arg is MapSpan mapSpan && handler is MapHandler mapHandler && mapHandler._mapControl != null) + { + double zoom = CalculateZoom(mapSpan); + + // Also set the DP values so they stay in sync for property reads + mapHandler._mapControl.Center = new Geopoint(new BasicGeoposition + { + Latitude = mapSpan.Center.Latitude, + Longitude = mapSpan.Center.Longitude + }); + mapHandler._mapControl.ZoomLevel = zoom; + + // Update VisibleRegion so the virtual view tracks the current map position + map.VisibleRegion = mapSpan; + + if (mapHandler._webViewReady) + { + _ = mapHandler.ExecuteJsAsync(string.Format( + CultureInfo.InvariantCulture, + "map.setCamera({{ center: [{0}, {1}], zoom: {2}, type: 'ease', duration: 300 }});", + mapSpan.Center.Longitude, mapSpan.Center.Latitude, zoom)); + } + else + { + // Queue it for when the WebView is ready + mapHandler._pendingSpan = mapSpan; + } + } + } + + /// + /// Maps the collection and handles dynamic updates to the Pins collection + /// when invoked by the handler. + /// + public static void MapPins(IMapHandler handler, IMap map) + { + if (handler is MapHandler mapHandler) + { + mapHandler.UpdatePins(map.Pins); + } + } + + void UpdatePins(IList pins) + { + if (_pinsLayer == null || _mapControl == null) + return; + + // Remove each MapIcon individually to trigger proper visual refresh. + // Layer recreation and MapElements.Clear() do not reliably update the WinUI 3 MapControl rendering. + foreach (var icon in _mapIcons) + { + _pinsLayer.MapElements.Remove(icon); + } + _mapIcons.Clear(); + + foreach (var pin in pins) + { + AddPinToLayer(pin); + } + } + + void AddPinToLayer(IMapPin pin) + { + if (_pinsLayer == null) + return; + + var mapIcon = new MapIcon + { + Location = new Geopoint(new BasicGeoposition + { + Latitude = pin.Location.Latitude, + Longitude = pin.Location.Longitude + }) + }; + + pin.MarkerId = mapIcon; + _mapIcons.Add(mapIcon); + _pinsLayer.MapElements.Add(mapIcon); + } + + /// + /// Maps the collection. No-op on Windows: the WinUI 3 only supports , not shapes. + /// + public static void MapElements(IMapHandler handler, IMap map) + { + // No-op: shapes (polylines, polygons, circles) are not supported by WinUI 3 MapElementsLayer. + } + + /// + public void UpdateMapElement(IMapElement element) + { + // No-op: shape rendering is not supported by the WinUI 3 MapControl. + } } } diff --git a/src/Core/maps/src/Handlers/MapElement/MapElementHandler.Windows.cs b/src/Core/maps/src/Handlers/MapElement/MapElementHandler.Windows.cs index eaf8d85e3e59..7cdbca0d9578 100644 --- a/src/Core/maps/src/Handlers/MapElement/MapElementHandler.Windows.cs +++ b/src/Core/maps/src/Handlers/MapElement/MapElementHandler.Windows.cs @@ -1,12 +1,82 @@ using Microsoft.Maui.Handlers; +using Microsoft.UI.Xaml.Controls; namespace Microsoft.Maui.Maps.Handlers { + /// + /// Handler for map elements (polylines, polygons, circles) on Windows. + /// + /// + /// + /// Platform Limitations (Windows/WinUI 3): + /// + /// Polylines: The WinUI 3 MapElementsLayer does not support polylines directly. + /// To render polylines, consider using Azure Maps REST API, Web SDK in a WebView, or custom XAML overlays. + /// Polygons: The WinUI 3 MapElementsLayer does not support polygons directly. + /// To render polygons, consider using Azure Maps REST API, Web SDK in a WebView, or custom XAML overlays. + /// Circles: The WinUI 3 MapElementsLayer does not support circles directly. + /// To render circles, approximate with a polygon or use Azure Maps REST API. + /// Stroke/Fill: MapIcon (the only fully supported element type) does not support + /// stroke or fill properties. These properties are no-ops on Windows. + /// + /// + /// + /// The current implementation returns a MapIcon as a placeholder. For full shape support, + /// consider integrating the Azure Maps Web SDK via a WebView control. + /// + /// public partial class MapElementHandler : ElementHandler { - protected override object CreatePlatformElement() => throw new System.NotImplementedException(); - public static void MapStroke(IMapElementHandler handler, IMapElement mapElement) => throw new System.NotImplementedException(); - public static void MapStrokeThickness(IMapElementHandler handler, IMapElement mapElement) => throw new System.NotImplementedException(); - public static void MapFill(IMapElementHandler handler, IMapElement mapElement) => throw new System.NotImplementedException(); + /// + /// + /// Windows Limitation: Returns a MapIcon as a placeholder since the WinUI 3 MapControl + /// does not support polylines, polygons, or circles in MapElementsLayer. + /// + protected override object CreatePlatformElement() + { + // The WinUI 3 MapControl primarily supports MapIcon through MapElementsLayer + // For polylines, polygons, and circles, we return a minimal MapElement + // Full shape support would require additional Azure Maps integration + return new MapIcon(); + } + + /// + /// Maps the property to the platform element. + /// + /// + /// Windows Limitation: Stroke is not supported on MapIcon. + /// This method is a no-op on Windows. For shape rendering, use Azure Maps Web SDK. + /// + public static void MapStroke(IMapElementHandler handler, IMapElement mapElement) + { + // Stroke is not directly supported on MapIcon + // Would need custom shape implementation for polylines/polygons + } + + /// + /// Maps the property to the platform element. + /// + /// + /// Windows Limitation: Stroke thickness is not supported on MapIcon. + /// This method is a no-op on Windows. For shape rendering, use Azure Maps Web SDK. + /// + public static void MapStrokeThickness(IMapElementHandler handler, IMapElement mapElement) + { + // Stroke thickness is not directly supported on MapIcon + // Would need custom shape implementation for polylines/polygons + } + + /// + /// Maps the property to the platform element. + /// + /// + /// Windows Limitation: Fill is not supported on MapIcon. + /// This method is a no-op on Windows. For shape rendering, use Azure Maps Web SDK. + /// + public static void MapFill(IMapElementHandler handler, IMapElement mapElement) + { + // Fill is not directly supported on MapIcon + // Would need custom shape implementation for polygons/circles + } } } diff --git a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Windows.cs b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Windows.cs index 37ac75d1300f..bfd83d1c30d5 100644 --- a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Windows.cs +++ b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Windows.cs @@ -1,15 +1,81 @@ using Microsoft.Maui.Handlers; +using Microsoft.UI.Xaml.Controls; +using Windows.Devices.Geolocation; namespace Microsoft.Maui.Maps.Handlers { + /// + /// Handler for map pins on Windows using the WinUI 3 MapIcon. + /// + /// + /// + /// Platform Limitations (Windows/WinUI 3): + /// + /// Label: MapIcon does not have a built-in label property. + /// To display pin labels, use a custom XAML overlay or tooltip. + /// Address: MapIcon does not display address information. + /// Address display requires custom UI implementation. + /// Custom Icons: MapIcon has limited customization. + /// Custom pin images require additional platform-specific code. + /// Info Windows: Tap-to-show-info-window pattern is not built-in. + /// Implement custom flyouts or popups for pin information display. + /// + /// + /// public partial class MapPinHandler : ElementHandler { - protected override object CreatePlatformElement() => throw new System.NotImplementedException(); + /// + protected override object CreatePlatformElement() + { + return new MapIcon + { + Location = new Geopoint(new BasicGeoposition + { + Latitude = VirtualView.Location.Latitude, + Longitude = VirtualView.Location.Longitude + }) + }; + } - public static void MapLocation(IMapPinHandler handler, IMapPin mapPin) { } + /// + /// Maps the property to the platform element. + /// + public static void MapLocation(IMapPinHandler handler, IMapPin mapPin) + { + if (handler.PlatformView is MapIcon mapIcon) + { + mapIcon.Location = new Geopoint(new BasicGeoposition + { + Latitude = mapPin.Location.Latitude, + Longitude = mapPin.Location.Longitude + }); + } + } - public static void MapLabel(IMapPinHandler handler, IMapPin mapPin) { } + /// + /// Maps the property to the platform element. + /// + /// + /// Windows Limitation: The WinUI 3 MapIcon does not support labels directly. + /// This method is a no-op on Windows. To display labels, implement a custom overlay. + /// + public static void MapLabel(IMapPinHandler handler, IMapPin mapPin) + { + // The WinUI 3 MapIcon doesn't have a direct label property + // Labels would need to be displayed via tooltips or custom UI overlay + } - public static void MapAddress(IMapPinHandler handler, IMapPin mapPin) { } + /// + /// Maps the property to the platform element. + /// + /// + /// Windows Limitation: The WinUI 3 MapIcon does not support address display. + /// This method is a no-op on Windows. To display addresses, implement a custom overlay or info window. + /// + public static void MapAddress(IMapPinHandler handler, IMapPin mapPin) + { + // The WinUI 3 MapIcon doesn't have an address property + // Address display would need custom implementation + } } }