XAML-Map-Control/MapControl/WinUI/MapBase.WinUI.cs

364 lines
12 KiB
C#
Raw Normal View History

2025-02-27 18:46:32 +01:00
#if UWP
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
2024-05-21 13:51:10 +02:00
using Windows.UI.Xaml.Media.Animation;
2024-05-22 11:25:32 +02:00
#else
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Animation;
2021-06-14 21:41:37 +02:00
#endif
2026-04-13 17:14:49 +02:00
namespace MapControl;
public partial class MapBase
{
2026-04-13 17:14:49 +02:00
public static readonly DependencyProperty ForegroundProperty =
DependencyPropertyHelper.Register<MapBase, Brush>(nameof(Foreground),
new SolidColorBrush(Colors.Black));
2024-05-24 15:14:05 +02:00
2026-04-13 17:14:49 +02:00
public static readonly DependencyProperty AnimationEasingFunctionProperty =
DependencyPropertyHelper.Register<MapBase, EasingFunctionBase>(nameof(AnimationEasingFunction),
new QuadraticEase { EasingMode = EasingMode.EaseOut });
2026-04-13 17:14:49 +02:00
public static readonly DependencyProperty CenterProperty =
DependencyPropertyHelper.Register<MapBase, Location>(nameof(Center), new Location(0d, 0d),
(map, oldValue, newValue) => map.CenterPropertyChanged(newValue));
2026-04-13 17:14:49 +02:00
public static readonly DependencyProperty TargetCenterProperty =
DependencyPropertyHelper.Register<MapBase, Location>(nameof(TargetCenter), new Location(0d, 0d),
(map, oldValue, newValue) => map.TargetCenterPropertyChanged(newValue));
2026-04-13 17:14:49 +02:00
public static readonly DependencyProperty MinZoomLevelProperty =
DependencyPropertyHelper.Register<MapBase, double>(nameof(MinZoomLevel), 1d,
(map, oldValue, newValue) => map.MinZoomLevelPropertyChanged(newValue));
2026-04-13 17:14:49 +02:00
public static readonly DependencyProperty MaxZoomLevelProperty =
DependencyPropertyHelper.Register<MapBase, double>(nameof(MaxZoomLevel), 20d,
(map, oldValue, newValue) => map.MaxZoomLevelPropertyChanged(newValue));
2026-04-13 17:14:49 +02:00
public static readonly DependencyProperty ZoomLevelProperty =
DependencyPropertyHelper.Register<MapBase, double>(nameof(ZoomLevel), 1d,
(map, oldValue, newValue) => map.ZoomLevelPropertyChanged(newValue));
2026-04-13 17:14:49 +02:00
public static readonly DependencyProperty TargetZoomLevelProperty =
DependencyPropertyHelper.Register<MapBase, double>(nameof(TargetZoomLevel), 1d,
(map, oldValue, newValue) => map.TargetZoomLevelPropertyChanged(newValue));
2022-11-02 19:49:18 +01:00
2026-04-13 17:14:49 +02:00
public static readonly DependencyProperty HeadingProperty =
DependencyPropertyHelper.Register<MapBase, double>(nameof(Heading), 0d,
(map, oldValue, newValue) => map.HeadingPropertyChanged(newValue));
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
public static readonly DependencyProperty TargetHeadingProperty =
DependencyPropertyHelper.Register<MapBase, double>(nameof(TargetHeading), 0d,
(map, oldValue, newValue) => map.TargetHeadingPropertyChanged(newValue));
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
public static readonly DependencyProperty ViewScaleProperty =
DependencyPropertyHelper.Register<MapBase, double>(nameof(ViewScale));
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
private static readonly DependencyProperty AnimatedCenterProperty =
DependencyPropertyHelper.Register<MapBase, Windows.Foundation.Point>(nameof(AnimatedCenter),
new Windows.Foundation.Point(),
(map, oldValue, newValue) => map.Center = new Location(newValue.Y, newValue.X));
2024-05-21 14:06:36 +02:00
2026-04-13 17:14:49 +02:00
private Windows.Foundation.Point AnimatedCenter => (Windows.Foundation.Point)GetValue(AnimatedCenterProperty);
2024-05-21 14:06:36 +02:00
2026-04-13 17:14:49 +02:00
private PointAnimation centerAnimation;
private DoubleAnimation zoomLevelAnimation;
private DoubleAnimation headingAnimation;
2026-04-13 17:14:49 +02:00
public MapBase()
{
// Set Background by Style to enable resetting by ClearValue in MapLayerPropertyChanged.
// There is no default Style in Generic.xaml because MapBase has no DefaultStyleKey property.
//
var style = new Style(typeof(MapBase));
style.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.White)));
style.Seal();
Style = style;
SizeChanged += OnSizeChanged;
}
2017-10-07 17:43:28 +02:00
2026-04-13 17:14:49 +02:00
/// <summary>
/// Gets or sets the EasingFunction of the Center, ZoomLevel and Heading animations.
/// The default value is a QuadraticEase with EasingMode.EaseOut.
/// </summary>
public EasingFunctionBase AnimationEasingFunction
{
get => (EasingFunctionBase)GetValue(AnimationEasingFunctionProperty);
set => SetValue(AnimationEasingFunctionProperty, value);
}
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
/// <summary>
/// Gets the scaling factor from projected map coordinates to view coordinates,
/// as pixels per meter.
/// </summary>
public double ViewScale
{
get => (double)GetValue(ViewScaleProperty);
private set => SetValue(ViewScaleProperty, value);
}
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
Clip = new RectangleGeometry
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
Rect = new Windows.Foundation.Rect(0d, 0d, e.NewSize.Width, e.NewSize.Height)
};
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
ResetTransformCenter();
UpdateTransform();
}
private void CenterPropertyChanged(Location value)
{
if (!internalPropertyChange)
2021-06-14 21:41:37 +02:00
{
2026-04-13 17:14:49 +02:00
var center = CoerceCenterProperty(value);
if (!center.Equals(value))
2021-06-14 21:41:37 +02:00
{
2026-04-13 17:14:49 +02:00
SetValueInternal(CenterProperty, center);
}
2021-06-14 21:41:37 +02:00
UpdateTransform();
2026-04-13 17:14:49 +02:00
if (centerAnimation == null)
{
SetValueInternal(TargetCenterProperty, center);
}
}
2026-04-13 17:14:49 +02:00
}
2022-11-02 19:49:18 +01:00
2026-04-13 17:14:49 +02:00
private void TargetCenterPropertyChanged(Location value)
{
if (!internalPropertyChange)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
ResetTransformCenter();
var targetCenter = CoerceCenterProperty(value);
if (!targetCenter.Equals(value))
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
SetValueInternal(TargetCenterProperty, targetCenter);
}
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
if (!targetCenter.Equals(Center))
{
if (centerAnimation != null)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
centerAnimation.Completed -= CenterAnimationCompleted;
2024-05-21 13:51:10 +02:00
}
2026-04-13 17:14:49 +02:00
centerAnimation = new PointAnimation
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
From = new Windows.Foundation.Point(Center.Longitude, Center.Latitude),
To = new Windows.Foundation.Point(NearestLongitude(targetCenter.Longitude), targetCenter.Latitude),
Duration = AnimationDuration,
EasingFunction = AnimationEasingFunction,
EnableDependentAnimation = true
};
centerAnimation.Completed += CenterAnimationCompleted;
BeginAnimation(nameof(AnimatedCenter), centerAnimation);
2024-05-21 13:51:10 +02:00
}
}
2026-04-13 17:14:49 +02:00
}
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
private void CenterAnimationCompleted(object sender, object e)
{
if (centerAnimation != null)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
centerAnimation.Completed -= CenterAnimationCompleted;
centerAnimation = null;
2026-04-13 17:14:49 +02:00
SetValueInternal(CenterProperty, TargetCenter);
UpdateTransform();
}
}
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
private void MinZoomLevelPropertyChanged(double value)
{
var minZoomLevel = CoerceMinZoomLevelProperty(value);
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
if (minZoomLevel != value)
{
SetValueInternal(MinZoomLevelProperty, minZoomLevel);
2024-05-21 13:51:10 +02:00
}
2026-04-13 17:14:49 +02:00
if (ZoomLevel < minZoomLevel)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
ZoomLevel = minZoomLevel;
2024-05-21 13:51:10 +02:00
}
2026-04-13 17:14:49 +02:00
}
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
private void MaxZoomLevelPropertyChanged(double value)
{
var maxZoomLevel = CoerceMaxZoomLevelProperty(value);
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
if (maxZoomLevel != value)
{
SetValueInternal(MaxZoomLevelProperty, maxZoomLevel);
}
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
if (ZoomLevel > maxZoomLevel)
{
ZoomLevel = maxZoomLevel;
2024-05-21 13:51:10 +02:00
}
2026-04-13 17:14:49 +02:00
}
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
private void ZoomLevelPropertyChanged(double value)
{
if (!internalPropertyChange)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
var zoomLevel = CoerceZoomLevelProperty(value);
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
if (zoomLevel != value)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
SetValueInternal(ZoomLevelProperty, zoomLevel);
2024-05-21 13:51:10 +02:00
}
2026-04-13 17:14:49 +02:00
UpdateTransform();
if (zoomLevelAnimation == null)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
SetValueInternal(TargetZoomLevelProperty, zoomLevel);
2024-05-21 13:51:10 +02:00
}
}
2026-04-13 17:14:49 +02:00
}
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
private void TargetZoomLevelPropertyChanged(double value)
{
if (!internalPropertyChange)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
var targetZoomLevel = CoerceZoomLevelProperty(value);
if (targetZoomLevel != value)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
SetValueInternal(TargetZoomLevelProperty, targetZoomLevel);
}
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
if (targetZoomLevel != ZoomLevel)
{
if (zoomLevelAnimation != null)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
2024-05-21 13:51:10 +02:00
}
2026-04-13 17:14:49 +02:00
zoomLevelAnimation = new DoubleAnimation
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
To = targetZoomLevel,
Duration = AnimationDuration,
EasingFunction = AnimationEasingFunction,
EnableDependentAnimation = true
};
zoomLevelAnimation.Completed += ZoomLevelAnimationCompleted;
BeginAnimation(nameof(ZoomLevel), zoomLevelAnimation);
2024-05-21 13:51:10 +02:00
}
}
2026-04-13 17:14:49 +02:00
}
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
private void ZoomLevelAnimationCompleted(object sender, object e)
{
if (zoomLevelAnimation != null)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
zoomLevelAnimation = null;
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
SetValueInternal(ZoomLevelProperty, TargetZoomLevel);
UpdateTransform(true);
2024-05-21 13:51:10 +02:00
}
2026-04-13 17:14:49 +02:00
}
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
private void HeadingPropertyChanged(double value)
{
if (!internalPropertyChange)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
var heading = CoerceHeadingProperty(value);
if (heading != value)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
SetValueInternal(HeadingProperty, heading);
}
2024-06-17 08:48:32 +02:00
2026-04-13 17:14:49 +02:00
UpdateTransform();
if (headingAnimation == null)
{
SetValueInternal(TargetHeadingProperty, heading);
2024-05-21 13:51:10 +02:00
}
}
2026-04-13 17:14:49 +02:00
}
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
private void TargetHeadingPropertyChanged(double value)
{
if (!internalPropertyChange)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
var targetHeading = CoerceHeadingProperty(value);
if (targetHeading != value)
{
SetValueInternal(TargetHeadingProperty, targetHeading);
}
if (targetHeading != Heading)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
var delta = targetHeading - Heading;
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
if (delta > 180d)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
delta -= 360d;
2024-05-21 13:51:10 +02:00
}
2026-04-13 17:14:49 +02:00
else if (delta < -180d)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
delta += 360d;
2024-05-21 13:51:10 +02:00
}
2026-04-13 17:14:49 +02:00
if (headingAnimation != null)
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
headingAnimation.Completed -= HeadingAnimationCompleted;
2024-05-21 13:51:10 +02:00
}
2026-04-13 17:14:49 +02:00
headingAnimation = new DoubleAnimation
2024-05-21 13:51:10 +02:00
{
2026-04-13 17:14:49 +02:00
By = delta,
Duration = AnimationDuration,
EasingFunction = AnimationEasingFunction,
EnableDependentAnimation = true
};
2024-05-21 13:51:10 +02:00
2026-04-13 17:14:49 +02:00
headingAnimation.Completed += HeadingAnimationCompleted;
2024-06-17 08:48:32 +02:00
2026-04-13 17:14:49 +02:00
BeginAnimation(nameof(Heading), headingAnimation);
2024-05-21 13:51:10 +02:00
}
}
2026-04-13 17:14:49 +02:00
}
2024-05-21 22:05:01 +02:00
2026-04-13 17:14:49 +02:00
private void HeadingAnimationCompleted(object sender, object e)
{
if (headingAnimation != null)
2024-05-21 22:05:01 +02:00
{
2026-04-13 17:14:49 +02:00
headingAnimation.Completed -= HeadingAnimationCompleted;
headingAnimation = null;
2024-05-21 22:05:01 +02:00
2026-04-13 17:14:49 +02:00
SetValueInternal(HeadingProperty, TargetHeading);
UpdateTransform();
2024-05-21 22:05:01 +02:00
}
}
2026-04-13 17:14:49 +02:00
private void BeginAnimation(string property, Timeline animation)
{
Storyboard.SetTarget(animation, this);
Storyboard.SetTargetProperty(animation, property);
var storyboard = new Storyboard();
storyboard.Children.Add(animation);
storyboard.Begin();
}
}