mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2026-04-05 14:37:01 +00:00
MapBase dependency properties
This commit is contained in:
parent
abe3bb75f9
commit
74f4e0176b
14 changed files with 1262 additions and 1037 deletions
|
|
@ -14,41 +14,21 @@ namespace MapControl
|
|||
{
|
||||
internal static class Animatable
|
||||
{
|
||||
public static void BeginAnimation(this DependencyObject obj, string property, Timeline animation)
|
||||
{
|
||||
Storyboard.SetTargetProperty(animation, property);
|
||||
Storyboard.SetTarget(animation, obj);
|
||||
|
||||
var storyboard = new Storyboard();
|
||||
storyboard.Children.Add(animation);
|
||||
storyboard.Begin();
|
||||
}
|
||||
|
||||
public static void BeginAnimation(this DependencyObject obj, DependencyProperty property, Timeline animation)
|
||||
{
|
||||
if (animation != null)
|
||||
if (animation != null && property == UIElement.OpacityProperty)
|
||||
{
|
||||
string propertyName = null;
|
||||
|
||||
if (property == MapBase.CenterPointProperty)
|
||||
{
|
||||
propertyName = "CenterPoint";
|
||||
((PointAnimation)animation).EnableDependentAnimation = true;
|
||||
}
|
||||
else if (property == MapBase.ZoomLevelProperty)
|
||||
{
|
||||
propertyName = "ZoomLevel";
|
||||
((DoubleAnimation)animation).EnableDependentAnimation = true;
|
||||
}
|
||||
else if (property == MapBase.HeadingProperty)
|
||||
{
|
||||
propertyName = "Heading";
|
||||
((DoubleAnimation)animation).EnableDependentAnimation = true;
|
||||
}
|
||||
else if (property == UIElement.OpacityProperty)
|
||||
{
|
||||
propertyName = "Opacity";
|
||||
}
|
||||
|
||||
if (propertyName != null)
|
||||
{
|
||||
Storyboard.SetTargetProperty(animation, propertyName);
|
||||
Storyboard.SetTarget(animation, obj);
|
||||
|
||||
var storyboard = new Storyboard();
|
||||
storyboard.Children.Add(animation);
|
||||
storyboard.Begin();
|
||||
}
|
||||
BeginAnimation(obj, nameof(UIElement.Opacity), animation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
44
MapControl/WinUI/DependencyPropertyHelper.WinUI.cs
Normal file
44
MapControl/WinUI/DependencyPropertyHelper.WinUI.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// Copyright © 2024 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
#if WINUI
|
||||
using Microsoft.UI.Xaml;
|
||||
#else
|
||||
using Windows.UI.Xaml;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public static class DependencyPropertyHelper
|
||||
{
|
||||
public static DependencyProperty Register<TOwner, TValue>(
|
||||
string name,
|
||||
TValue defaultValue = default,
|
||||
bool bindTwoWayByDefault = false,
|
||||
Action<TOwner, TValue, TValue> changed = null)
|
||||
where TOwner : DependencyObject
|
||||
{
|
||||
var metadata = changed != null
|
||||
? new PropertyMetadata(defaultValue, (o, e) => changed((TOwner)o, (TValue)e.OldValue, (TValue)e.NewValue))
|
||||
: new PropertyMetadata(defaultValue);
|
||||
|
||||
return DependencyProperty.Register(name, typeof(TValue), typeof(TOwner), metadata);
|
||||
}
|
||||
|
||||
public static DependencyProperty RegisterAttached<TOwner, TValue>(
|
||||
string name,
|
||||
TValue defaultValue = default,
|
||||
bool inherits = false,
|
||||
Action<FrameworkElement, TValue, TValue> changed = null)
|
||||
where TOwner : DependencyObject
|
||||
{
|
||||
var metadata = changed != null
|
||||
? new PropertyMetadata(defaultValue, (o, e) => changed((FrameworkElement)o, (TValue)e.OldValue, (TValue)e.NewValue))
|
||||
: new PropertyMetadata(defaultValue);
|
||||
|
||||
return DependencyProperty.RegisterAttached(name, typeof(TValue), typeof(TOwner), metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,50 +6,60 @@
|
|||
using Microsoft.UI;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
#else
|
||||
using Windows.UI;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class MapBase
|
||||
{
|
||||
public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(
|
||||
nameof(Center), typeof(Location), typeof(MapBase),
|
||||
new PropertyMetadata(new Location(), (o, e) => ((MapBase)o).CenterPropertyChanged((Location)e.NewValue)));
|
||||
public static readonly DependencyProperty AnimationEasingFunctionProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, EasingFunctionBase>(nameof(AnimationEasingFunction),
|
||||
new QuadraticEase { EasingMode = EasingMode.EaseOut });
|
||||
|
||||
public static readonly DependencyProperty TargetCenterProperty = DependencyProperty.Register(
|
||||
nameof(TargetCenter), typeof(Location), typeof(MapBase),
|
||||
new PropertyMetadata(new Location(), (o, e) => ((MapBase)o).TargetCenterPropertyChanged((Location)e.NewValue)));
|
||||
public static readonly DependencyProperty CenterProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, Location>(nameof(Center), new Location(), true,
|
||||
(map, oldValue, newValue) => map.CenterPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty ZoomLevelProperty = DependencyProperty.Register(
|
||||
nameof(ZoomLevel), typeof(double), typeof(MapBase),
|
||||
new PropertyMetadata(1d, (o, e) => ((MapBase)o).ZoomLevelPropertyChanged((double)e.NewValue)));
|
||||
public static readonly DependencyProperty TargetCenterProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, Location>(nameof(TargetCenter), new Location(), true,
|
||||
(map, oldValue, newValue) => map.TargetCenterPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty TargetZoomLevelProperty = DependencyProperty.Register(
|
||||
nameof(TargetZoomLevel), typeof(double), typeof(MapBase),
|
||||
new PropertyMetadata(1d, (o, e) => ((MapBase)o).TargetZoomLevelPropertyChanged((double)e.NewValue)));
|
||||
public static readonly DependencyProperty MinZoomLevelProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(MinZoomLevel), 1d, false,
|
||||
(map, oldValue, newValue) => map.MinZoomLevelPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty HeadingProperty = DependencyProperty.Register(
|
||||
nameof(Heading), typeof(double), typeof(MapBase),
|
||||
new PropertyMetadata(0d, (o, e) => ((MapBase)o).HeadingPropertyChanged((double)e.NewValue)));
|
||||
public static readonly DependencyProperty MaxZoomLevelProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(MaxZoomLevel), 20d, false,
|
||||
(map, oldValue, newValue) => map.MaxZoomLevelPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty TargetHeadingProperty = DependencyProperty.Register(
|
||||
nameof(TargetHeading), typeof(double), typeof(MapBase),
|
||||
new PropertyMetadata(0d, (o, e) => ((MapBase)o).TargetHeadingPropertyChanged((double)e.NewValue)));
|
||||
public static readonly DependencyProperty ZoomLevelProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(ZoomLevel), 1d, true,
|
||||
(map, oldValue, newValue) => map.ZoomLevelPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty ViewScaleProperty = DependencyProperty.Register(
|
||||
nameof(ViewScale), typeof(double), typeof(MapBase), new PropertyMetadata(0d));
|
||||
public static readonly DependencyProperty TargetZoomLevelProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(TargetZoomLevel), 1d, true,
|
||||
(map, oldValue, newValue) => map.TargetZoomLevelPropertyChanged(newValue));
|
||||
|
||||
internal static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register(
|
||||
"CenterPoint", typeof(Windows.Foundation.Point), typeof(MapBase),
|
||||
new PropertyMetadata(new Windows.Foundation.Point(), (o, e) =>
|
||||
{
|
||||
var center = (Windows.Foundation.Point)e.NewValue;
|
||||
((MapBase)o).CenterPointPropertyChanged(new Location(center.Y, center.X));
|
||||
}));
|
||||
public static readonly DependencyProperty HeadingProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(Heading), 0d, true,
|
||||
(map, oldValue, newValue) => map.HeadingPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty TargetHeadingProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(TargetHeading), 0d, true,
|
||||
(map, oldValue, newValue) => map.TargetHeadingPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty ViewScaleProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(ViewScale), 0d);
|
||||
|
||||
private PointAnimation centerAnimation;
|
||||
private DoubleAnimation zoomLevelAnimation;
|
||||
private DoubleAnimation headingAnimation;
|
||||
|
||||
public MapBase()
|
||||
{
|
||||
|
|
@ -62,6 +72,36 @@ namespace MapControl
|
|||
SizeChanged += OnSizeChanged;
|
||||
}
|
||||
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scaling factor from projected map coordinates to view coordinates,
|
||||
/// as pixels per meter.
|
||||
/// </summary>
|
||||
public double ViewScale => (double)GetValue(ViewScaleProperty);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a transform Matrix for scaling and rotating objects that are anchored
|
||||
/// at a Location from map coordinates (i.e. meters) to view coordinates.
|
||||
/// </summary>
|
||||
public Matrix GetMapTransform(Location location)
|
||||
{
|
||||
var scale = GetScale(location);
|
||||
|
||||
var transform = new Matrix(scale.X, 0d, 0d, scale.Y, 0d, 0d);
|
||||
transform.Rotate(ViewTransform.Rotation);
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
Clip = new RectangleGeometry
|
||||
|
|
@ -77,5 +117,248 @@ namespace MapControl
|
|||
{
|
||||
SetValue(ViewScaleProperty, scale);
|
||||
}
|
||||
|
||||
private void CenterPropertyChanged(Location value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
var center = CoerceCenterProperty(value);
|
||||
|
||||
if (!center.Equals(value))
|
||||
{
|
||||
SetValueInternal(CenterProperty, center);
|
||||
}
|
||||
|
||||
UpdateTransform();
|
||||
|
||||
if (centerAnimation == null)
|
||||
{
|
||||
SetValueInternal(TargetCenterProperty, center);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable IDE0052 // Remove unread private members
|
||||
private static readonly DependencyProperty CenterPointProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, Windows.Foundation.Point>("CenterPoint",
|
||||
new Windows.Foundation.Point(), false, (map, oldValue, newValue) => map.Center = new Location(newValue.Y, newValue.X));
|
||||
#pragma warning restore IDE0052
|
||||
|
||||
private void TargetCenterPropertyChanged(Location value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
var targetCenter = CoerceCenterProperty(value);
|
||||
|
||||
if (!targetCenter.Equals(value))
|
||||
{
|
||||
SetValueInternal(TargetCenterProperty, targetCenter);
|
||||
}
|
||||
|
||||
if (!targetCenter.Equals(Center))
|
||||
{
|
||||
if (centerAnimation != null)
|
||||
{
|
||||
centerAnimation.Completed -= CenterAnimationCompleted;
|
||||
}
|
||||
|
||||
centerAnimation = new PointAnimation
|
||||
{
|
||||
From = new Windows.Foundation.Point(Center.Longitude, Center.Latitude),
|
||||
To = new Windows.Foundation.Point(ConstrainedLongitude(targetCenter.Longitude), targetCenter.Latitude),
|
||||
Duration = AnimationDuration,
|
||||
EasingFunction = AnimationEasingFunction,
|
||||
EnableDependentAnimation = true
|
||||
};
|
||||
|
||||
centerAnimation.Completed += CenterAnimationCompleted;
|
||||
|
||||
this.BeginAnimation("CenterPoint", centerAnimation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CenterAnimationCompleted(object sender, object e)
|
||||
{
|
||||
if (centerAnimation != null)
|
||||
{
|
||||
SetValueInternal(CenterProperty, TargetCenter);
|
||||
UpdateTransform();
|
||||
|
||||
centerAnimation.Completed -= CenterAnimationCompleted;
|
||||
centerAnimation = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void MinZoomLevelPropertyChanged(double value)
|
||||
{
|
||||
var minZoomLevel = CoerceMinZoomLevelProperty(value);
|
||||
|
||||
if (minZoomLevel != value)
|
||||
{
|
||||
SetValueInternal(MinZoomLevelProperty, minZoomLevel);
|
||||
}
|
||||
|
||||
if (ZoomLevel < minZoomLevel)
|
||||
{
|
||||
ZoomLevel = minZoomLevel;
|
||||
}
|
||||
}
|
||||
|
||||
private void MaxZoomLevelPropertyChanged(double value)
|
||||
{
|
||||
var maxZoomLevel = CoerceMaxZoomLevelProperty(value);
|
||||
|
||||
if (maxZoomLevel != value)
|
||||
{
|
||||
SetValueInternal(MaxZoomLevelProperty, maxZoomLevel);
|
||||
}
|
||||
|
||||
if (ZoomLevel > maxZoomLevel)
|
||||
{
|
||||
ZoomLevel = maxZoomLevel;
|
||||
}
|
||||
}
|
||||
|
||||
private void ZoomLevelPropertyChanged(double value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
var zoomLevel = CoerceZoomLevelProperty(value);
|
||||
|
||||
if (zoomLevel != value)
|
||||
{
|
||||
SetValueInternal(ZoomLevelProperty, zoomLevel);
|
||||
}
|
||||
|
||||
UpdateTransform();
|
||||
|
||||
if (zoomLevelAnimation == null)
|
||||
{
|
||||
SetValueInternal(TargetZoomLevelProperty, zoomLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TargetZoomLevelPropertyChanged(double value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
var targetZoomLevel = CoerceZoomLevelProperty(value);
|
||||
|
||||
if (targetZoomLevel != value)
|
||||
{
|
||||
SetValueInternal(TargetZoomLevelProperty, targetZoomLevel);
|
||||
}
|
||||
|
||||
if (targetZoomLevel != ZoomLevel)
|
||||
{
|
||||
if (zoomLevelAnimation != null)
|
||||
{
|
||||
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
|
||||
}
|
||||
|
||||
zoomLevelAnimation = new DoubleAnimation
|
||||
{
|
||||
To = targetZoomLevel,
|
||||
Duration = AnimationDuration,
|
||||
EasingFunction = AnimationEasingFunction,
|
||||
EnableDependentAnimation = true
|
||||
};
|
||||
|
||||
zoomLevelAnimation.Completed += ZoomLevelAnimationCompleted;
|
||||
|
||||
this.BeginAnimation(nameof(ZoomLevel), zoomLevelAnimation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ZoomLevelAnimationCompleted(object sender, object e)
|
||||
{
|
||||
if (zoomLevelAnimation != null)
|
||||
{
|
||||
SetValueInternal(ZoomLevelProperty, TargetZoomLevel);
|
||||
UpdateTransform(true);
|
||||
|
||||
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
|
||||
zoomLevelAnimation = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void HeadingPropertyChanged(double value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
var heading = CoerceHeadingProperty(value);
|
||||
|
||||
if (heading != value)
|
||||
{
|
||||
SetValueInternal(HeadingProperty, heading);
|
||||
}
|
||||
|
||||
UpdateTransform();
|
||||
|
||||
if (headingAnimation == null)
|
||||
{
|
||||
SetValueInternal(TargetHeadingProperty, heading);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TargetHeadingPropertyChanged(double value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
var targetHeading = CoerceHeadingProperty(value);
|
||||
|
||||
if (targetHeading != value)
|
||||
{
|
||||
SetValueInternal(TargetHeadingProperty, targetHeading);
|
||||
}
|
||||
|
||||
if (targetHeading != Heading)
|
||||
{
|
||||
var delta = targetHeading - Heading;
|
||||
|
||||
if (delta > 180d)
|
||||
{
|
||||
delta -= 360d;
|
||||
}
|
||||
else if (delta < -180d)
|
||||
{
|
||||
delta += 360d;
|
||||
}
|
||||
|
||||
if (headingAnimation != null)
|
||||
{
|
||||
headingAnimation.Completed -= HeadingAnimationCompleted;
|
||||
}
|
||||
|
||||
headingAnimation = new DoubleAnimation
|
||||
{
|
||||
By = delta,
|
||||
Duration = AnimationDuration,
|
||||
EasingFunction = AnimationEasingFunction,
|
||||
EnableDependentAnimation = true
|
||||
};
|
||||
|
||||
headingAnimation.Completed += HeadingAnimationCompleted;
|
||||
|
||||
this.BeginAnimation(nameof(Heading), headingAnimation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HeadingAnimationCompleted(object sender, object e)
|
||||
{
|
||||
if (headingAnimation != null)
|
||||
{
|
||||
SetValueInternal(HeadingProperty, TargetHeading);
|
||||
UpdateTransform();
|
||||
|
||||
headingAnimation.Completed -= HeadingAnimationCompleted;
|
||||
headingAnimation = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue