diff --git a/MapControl/Shared/MapBase.cs b/MapControl/Shared/MapBase.cs
index 6240fdb3..2e4e949e 100644
--- a/MapControl/Shared/MapBase.cs
+++ b/MapControl/Shared/MapBase.cs
@@ -236,6 +236,18 @@ namespace MapControl
return ViewTransform.Scale * MapProjection.GetRelativeScale(location);
}
+ ///
+ /// Gets a transform Matrix for scaling and rotating objects that are anchored
+ /// at a Location from map coordinates (i.e. meters) to view coordinates.
+ ///
+ public Matrix GetMapTransform(Location location)
+ {
+ var scale = GetScale(location);
+ var matrix = new Matrix(scale.X, 0d, 0d, scale.Y, 0d, 0d);
+ matrix.Rotate(ViewTransform.Rotation);
+ return matrix;
+ }
+
///
/// Transforms a Location in geographic coordinates to a Point in view coordinates.
///
diff --git a/MapControl/Shared/MapItem.cs b/MapControl/Shared/MapItem.cs
new file mode 100644
index 00000000..9a69cf3c
--- /dev/null
+++ b/MapControl/Shared/MapItem.cs
@@ -0,0 +1,105 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// Copyright © 2023 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+#if WINUI
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+#elif UWP
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media;
+#else
+using System.Windows.Controls;
+using System.Windows.Media;
+#endif
+
+namespace MapControl
+{
+ ///
+ /// Container class for an item in a MapItemsControl.
+ ///
+ public partial class MapItem : ListBoxItem, IMapElement
+ {
+ private MapBase parentMap;
+ private MatrixTransform mapTransform;
+
+ ///
+ /// Gets/sets MapPanel.AutoCollapse.
+ ///
+ public bool AutoCollapse
+ {
+ get => (bool)GetValue(AutoCollapseProperty);
+ set => SetValue(AutoCollapseProperty, value);
+ }
+
+ ///
+ /// Gets/sets MapPanel.Location.
+ ///
+ public Location Location
+ {
+ get => (Location)GetValue(LocationProperty);
+ set => SetValue(LocationProperty, value);
+ }
+
+ ///
+ /// Implements IMapElement.ParentMap.
+ ///
+ public MapBase ParentMap
+ {
+ get => parentMap;
+ set
+ {
+ if (parentMap != null)
+ {
+ parentMap.ViewportChanged -= OnViewportChanged;
+ }
+
+ parentMap = value;
+
+ if (parentMap != null && mapTransform != null)
+ {
+ // Attach ViewportChanged handler only if MapTransform is actually used.
+ //
+ parentMap.ViewportChanged += OnViewportChanged;
+ UpdateMapTransform(Location);
+ }
+ }
+ }
+
+ ///
+ /// Gets a Transform for scaling and rotating geometries
+ /// in map coordinates (meters) to view coordinates (pixels).
+ ///
+ public Transform MapTransform
+ {
+ get
+ {
+ if (mapTransform == null)
+ {
+ mapTransform = new MatrixTransform();
+
+ if (parentMap != null)
+ {
+ parentMap.ViewportChanged += OnViewportChanged;
+ UpdateMapTransform(Location);
+ }
+ }
+
+ return mapTransform;
+ }
+ }
+
+ private void OnViewportChanged(object sender, ViewportChangedEventArgs e)
+ {
+ UpdateMapTransform(Location);
+ }
+
+ private void UpdateMapTransform(Location location)
+ {
+ if (mapTransform != null && parentMap != null && location != null)
+ {
+ mapTransform.Matrix = parentMap.GetMapTransform(location);
+ }
+ }
+ }
+}
diff --git a/MapControl/Shared/MapItemsControl.cs b/MapControl/Shared/MapItemsControl.cs
index d4191289..c78b2815 100644
--- a/MapControl/Shared/MapItemsControl.cs
+++ b/MapControl/Shared/MapItemsControl.cs
@@ -8,77 +8,19 @@ using Windows.Foundation;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
-using Microsoft.UI.Xaml.Media;
#elif UWP
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
-using Windows.UI.Xaml.Media;
#else
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
-using System.Windows.Media;
#endif
namespace MapControl
{
- ///
- /// Container class for an item in a MapItemsControl.
- ///
- public partial class MapItem : ListBoxItem
- {
- ///
- /// Gets/sets MapPanel.AutoCollapse.
- ///
- public bool AutoCollapse
- {
- get => (bool)GetValue(AutoCollapseProperty);
- set => SetValue(AutoCollapseProperty, value);
- }
-
- ///
- /// Gets/sets MapPanel.Location.
- ///
- public Location Location
- {
- get => (Location)GetValue(LocationProperty);
- set => SetValue(LocationProperty, value);
- }
-
- ///
- /// Gets a Transform for scaling and rotating geometries
- /// in map coordinates (meters) to view coordinates (pixels).
- ///
- public Transform MapTransform => mapTransform ?? (mapTransform = new MatrixTransform());
-
- private MatrixTransform mapTransform;
-
- protected override Size ArrangeOverride(Size bounds)
- {
- var size = base.ArrangeOverride(bounds);
-
- // If the MapTransform property is used, update its Matrix property
- // (after calling base.ArrangeOverride to avoid rendering issues).
- //
- if (mapTransform != null)
- {
- var parentMap = (VisualTreeHelper.GetParent(this) as MapPanel)?.ParentMap;
-
- if (parentMap != null && Location != null)
- {
- var scale = parentMap.GetScale(Location);
- var matrix = new Matrix(scale.X, 0d, 0d, scale.Y, 0d, 0d);
- matrix.Rotate(parentMap.ViewTransform.Rotation);
- mapTransform.Matrix = matrix;
- }
- }
-
- return size;
- }
- }
-
///
/// Manages a collection of selectable items on a Map.
///
diff --git a/MapControl/Shared/MapPanel.cs b/MapControl/Shared/MapPanel.cs
index c7937892..581a37b8 100644
--- a/MapControl/Shared/MapPanel.cs
+++ b/MapControl/Shared/MapPanel.cs
@@ -46,6 +46,9 @@ namespace MapControl
private MapBase parentMap;
+ ///
+ /// Implements IMapElement.ParentMap.
+ ///
public MapBase ParentMap
{
get => parentMap;
diff --git a/MapControl/Shared/MapPath.cs b/MapControl/Shared/MapPath.cs
index c4d07c26..42e31746 100644
--- a/MapControl/Shared/MapPath.cs
+++ b/MapControl/Shared/MapPath.cs
@@ -40,6 +40,9 @@ namespace MapControl
set => SetValue(LocationProperty, value);
}
+ ///
+ /// Implements IMapElement.ParentMap.
+ ///
public MapBase ParentMap
{
get => parentMap;
@@ -72,9 +75,7 @@ namespace MapControl
if (parentMap != null && Location != null && Data != null)
{
- var scale = parentMap.GetScale(Location);
- var matrix = new Matrix(scale.X, 0d, 0d, scale.Y, 0d, 0d);
- matrix.Rotate(parentMap.ViewTransform.Rotation);
+ var matrix = parentMap.GetMapTransform(Location);
if (Data.Transform is MatrixTransform transform)
{
diff --git a/MapControl/Shared/MapTileLayerBase.cs b/MapControl/Shared/MapTileLayerBase.cs
index 8cdd1c07..9a9fc1ea 100644
--- a/MapControl/Shared/MapTileLayerBase.cs
+++ b/MapControl/Shared/MapTileLayerBase.cs
@@ -165,6 +165,9 @@ namespace MapControl
private set => SetValue(LoadingProgressProperty, value);
}
+ ///
+ /// Implements IMapElement.ParentMap.
+ ///
public MapBase ParentMap
{
get => parentMap;
diff --git a/MapControl/UWP/MapControl.UWP.csproj b/MapControl/UWP/MapControl.UWP.csproj
index 014af40b..3dda270e 100644
--- a/MapControl/UWP/MapControl.UWP.csproj
+++ b/MapControl/UWP/MapControl.UWP.csproj
@@ -113,6 +113,9 @@
MapImageLayer.cs
+
+ MapItem.cs
+
MapItemsControl.cs
@@ -248,6 +251,9 @@
MapGraticule.WinUI.cs
+
+ MapItem.WinUI.cs
+
MapItemsControl.WinUI.cs
diff --git a/MapControl/WPF/MapItem.WPF.cs b/MapControl/WPF/MapItem.WPF.cs
new file mode 100644
index 00000000..b37da483
--- /dev/null
+++ b/MapControl/WPF/MapItem.WPF.cs
@@ -0,0 +1,31 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// Copyright © 2023 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+
+namespace MapControl
+{
+ public partial class MapItem
+ {
+ public static readonly DependencyProperty AutoCollapseProperty = MapPanel.AutoCollapseProperty.AddOwner(
+ typeof(MapItem));
+
+ public static readonly DependencyProperty LocationProperty = MapPanel.LocationProperty.AddOwner(
+ typeof(MapItem), new FrameworkPropertyMetadata(null,
+ (o, e) => ((MapItem)o).UpdateMapTransform((Location)e.NewValue)));
+
+ static MapItem()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(MapItem), new FrameworkPropertyMetadata(typeof(MapItem)));
+ }
+
+ protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
+ {
+ (ItemsControl.ItemsControlFromItemContainer(this) as MapItemsControl)?.OnItemClicked(
+ this, Keyboard.Modifiers.HasFlag(ModifierKeys.Control), Keyboard.Modifiers.HasFlag(ModifierKeys.Shift));
+ }
+ }
+}
diff --git a/MapControl/WPF/MapItemsControl.WPF.cs b/MapControl/WPF/MapItemsControl.WPF.cs
index b7272340..57406e8e 100644
--- a/MapControl/WPF/MapItemsControl.WPF.cs
+++ b/MapControl/WPF/MapItemsControl.WPF.cs
@@ -4,29 +4,10 @@
using System.Windows;
using System.Windows.Controls;
-using System.Windows.Input;
using System.Windows.Media;
namespace MapControl
{
- public partial class MapItem
- {
- public static readonly DependencyProperty AutoCollapseProperty = MapPanel.AutoCollapseProperty.AddOwner(typeof(MapItem));
-
- public static readonly DependencyProperty LocationProperty = MapPanel.LocationProperty.AddOwner(typeof(MapItem));
-
- static MapItem()
- {
- DefaultStyleKeyProperty.OverrideMetadata(typeof(MapItem), new FrameworkPropertyMetadata(typeof(MapItem)));
- }
-
- protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
- {
- (ItemsControl.ItemsControlFromItemContainer(this) as MapItemsControl)?.OnItemClicked(
- this, Keyboard.Modifiers.HasFlag(ModifierKeys.Control), Keyboard.Modifiers.HasFlag(ModifierKeys.Shift));
- }
- }
-
public partial class MapItemsControl
{
static MapItemsControl()
diff --git a/MapControl/WinUI/MapItem.WinUI.cs b/MapControl/WinUI/MapItem.WinUI.cs
new file mode 100644
index 00000000..88424748
--- /dev/null
+++ b/MapControl/WinUI/MapItem.WinUI.cs
@@ -0,0 +1,65 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// Copyright © 2023 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using Windows.System;
+#if WINUI
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Input;
+#else
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Input;
+#endif
+
+namespace MapControl
+{
+ public partial class MapItem
+ {
+ public static readonly DependencyProperty AutoCollapseProperty = DependencyProperty.Register(
+ nameof(AutoCollapse), typeof(bool), typeof(MapItem), new PropertyMetadata(false,
+ (o, e) => MapPanel.SetAutoCollapse((MapItem)o, (bool)e.NewValue)));
+
+ public static readonly DependencyProperty LocationProperty = DependencyProperty.Register(
+ nameof(Location), typeof(Location), typeof(MapItem), new PropertyMetadata(null,
+ (o, e) => ((MapItem)o).LocationPropertyChanged((Location)e.NewValue)));
+
+ private void LocationPropertyChanged(Location location)
+ {
+ MapPanel.SetLocation(this, location);
+ UpdateMapTransform(location);
+ }
+
+ public MapItem()
+ {
+ DefaultStyleKey = typeof(MapItem);
+ MapPanel.InitMapElement(this);
+ }
+
+ protected override void OnPointerPressed(PointerRoutedEventArgs e)
+ {
+ (ItemsControl.ItemsControlFromItemContainer(this) as MapItemsControl)?.OnItemClicked(
+ this, e.KeyModifiers.HasFlag(VirtualKeyModifiers.Control), e.KeyModifiers.HasFlag(VirtualKeyModifiers.Shift));
+ }
+
+ protected override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ var parentMap = MapPanel.GetParentMap(this);
+
+ if (parentMap != null)
+ {
+ // If this.Background is not explicitly set, bind it to parentMap.Background
+ this.SetBindingOnUnsetProperty(BackgroundProperty, parentMap, Panel.BackgroundProperty, nameof(Background));
+
+ // If this.Foreground is not explicitly set, bind it to parentMap.Foreground
+ this.SetBindingOnUnsetProperty(ForegroundProperty, parentMap, MapBase.ForegroundProperty, nameof(Foreground));
+
+ // If this.BorderBrush is not explicitly set, bind it to parentMap.Foreground
+ this.SetBindingOnUnsetProperty(BorderBrushProperty, parentMap, MapBase.ForegroundProperty, nameof(Foreground));
+ }
+ }
+ }
+}
diff --git a/MapControl/WinUI/MapItemsControl.WinUI.cs b/MapControl/WinUI/MapItemsControl.WinUI.cs
index f9be6819..38b10ed0 100644
--- a/MapControl/WinUI/MapItemsControl.WinUI.cs
+++ b/MapControl/WinUI/MapItemsControl.WinUI.cs
@@ -2,61 +2,14 @@
// Copyright © 2023 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
-using Windows.System;
#if WINUI
using Microsoft.UI.Xaml;
-using Microsoft.UI.Xaml.Controls;
-using Microsoft.UI.Xaml.Input;
#else
using Windows.UI.Xaml;
-using Windows.UI.Xaml.Controls;
-using Windows.UI.Xaml.Input;
#endif
namespace MapControl
{
- public partial class MapItem
- {
- public static readonly DependencyProperty AutoCollapseProperty = DependencyProperty.Register(
- nameof(AutoCollapse), typeof(bool), typeof(MapItem),
- new PropertyMetadata(false, (o, e) => MapPanel.SetAutoCollapse((MapItem)o, (bool)e.NewValue)));
-
- public static readonly DependencyProperty LocationProperty = DependencyProperty.Register(
- nameof(Location), typeof(Location), typeof(MapItem),
- new PropertyMetadata(null, (o, e) => MapPanel.SetLocation((MapItem)o, (Location)e.NewValue)));
-
- public MapItem()
- {
- DefaultStyleKey = typeof(MapItem);
- MapPanel.InitMapElement(this);
- }
-
- protected override void OnPointerPressed(PointerRoutedEventArgs e)
- {
- (ItemsControl.ItemsControlFromItemContainer(this) as MapItemsControl)?.OnItemClicked(
- this, e.KeyModifiers.HasFlag(VirtualKeyModifiers.Control), e.KeyModifiers.HasFlag(VirtualKeyModifiers.Shift));
- }
-
- protected override void OnApplyTemplate()
- {
- base.OnApplyTemplate();
-
- var parentMap = MapPanel.GetParentMap(this);
-
- if (parentMap != null)
- {
- // If this.Background is not explicitly set, bind it to parentMap.Background
- this.SetBindingOnUnsetProperty(BackgroundProperty, parentMap, Panel.BackgroundProperty, nameof(Background));
-
- // If this.Foreground is not explicitly set, bind it to parentMap.Foreground
- this.SetBindingOnUnsetProperty(ForegroundProperty, parentMap, MapBase.ForegroundProperty, nameof(Foreground));
-
- // If this.BorderBrush is not explicitly set, bind it to parentMap.Foreground
- this.SetBindingOnUnsetProperty(BorderBrushProperty, parentMap, MapBase.ForegroundProperty, nameof(Foreground));
- }
- }
- }
-
public partial class MapItemsControl
{
public MapItemsControl()