From 8e4110b600867c8fafbe4d71f7860fe4e4ab18a1 Mon Sep 17 00:00:00 2001 From: ClemensFischer Date: Sat, 25 May 2024 15:55:31 +0200 Subject: [PATCH] Avalonia Pushpin --- .../Avalonia/MapContentControl.Avalonia.cs | 4 - .../Avalonia/MapControl.Avalonia.csproj | 1 - MapControl/Avalonia/PushpinBorder.Avalonia.cs | 107 +++++++++ MapControl/Avalonia/Themes/Generic.axaml | 49 ++++ MapControl/Shared/MapPanel.cs | 17 +- MapControl/Shared/PushpinBorder.cs | 3 + MapControl/WinUI/MapContentControl.WinUI.cs | 4 +- MapControl/WinUI/MapItem.WinUI.cs | 16 +- SampleApps/AvaloniaApp/App.axaml | 1 + SampleApps/AvaloniaApp/MainWindow.axaml | 218 +++++++++--------- 10 files changed, 287 insertions(+), 133 deletions(-) create mode 100644 MapControl/Avalonia/PushpinBorder.Avalonia.cs create mode 100644 MapControl/Avalonia/Themes/Generic.axaml diff --git a/MapControl/Avalonia/MapContentControl.Avalonia.cs b/MapControl/Avalonia/MapContentControl.Avalonia.cs index a925fd90..067c80d3 100644 --- a/MapControl/Avalonia/MapContentControl.Avalonia.cs +++ b/MapControl/Avalonia/MapContentControl.Avalonia.cs @@ -3,7 +3,6 @@ // Licensed under the Microsoft Public License (Ms-PL) using Avalonia.Controls; -using System; namespace MapControl { @@ -18,8 +17,6 @@ namespace MapControl public static readonly StyledProperty LocationProperty = DependencyPropertyHelper.AddOwner(MapPanel.LocationProperty); - protected override Type StyleKeyOverride => typeof(MapContentControl); - /// /// Gets/sets MapPanel.AutoCollapse. /// @@ -44,6 +41,5 @@ namespace MapControl /// public class Pushpin : MapContentControl { - protected override Type StyleKeyOverride => typeof(Pushpin); } } diff --git a/MapControl/Avalonia/MapControl.Avalonia.csproj b/MapControl/Avalonia/MapControl.Avalonia.csproj index 1c1f51a8..bfe0e043 100644 --- a/MapControl/Avalonia/MapControl.Avalonia.csproj +++ b/MapControl/Avalonia/MapControl.Avalonia.csproj @@ -31,7 +31,6 @@ - diff --git a/MapControl/Avalonia/PushpinBorder.Avalonia.cs b/MapControl/Avalonia/PushpinBorder.Avalonia.cs new file mode 100644 index 00000000..b7e347f7 --- /dev/null +++ b/MapControl/Avalonia/PushpinBorder.Avalonia.cs @@ -0,0 +1,107 @@ +// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control +// Copyright © 2024 Clemens Fischer +// Licensed under the Microsoft Public License (Ms-PL) + +using Avalonia.Controls; +using Avalonia.Media; +using System; + +namespace MapControl +{ + public partial class PushpinBorder : Decorator + { + public static readonly StyledProperty CornerRadiusProperty = + DependencyPropertyHelper.Register(nameof(CornerRadius), new CornerRadius()); + + public static readonly StyledProperty ArrowSizeProperty = + DependencyPropertyHelper.Register(nameof(ArrowSize), new Size(10d, 20d)); + + public static readonly StyledProperty BorderWidthProperty = + DependencyPropertyHelper.Register(nameof(BorderWidth)); + + public static readonly StyledProperty BackgroundProperty = + DependencyPropertyHelper.Register(nameof(Background)); + + public static readonly StyledProperty BorderBrushProperty = + DependencyPropertyHelper.Register(nameof(BorderBrush)); + + static PushpinBorder() + { + AffectsMeasure(ArrowSizeProperty, BorderWidthProperty, CornerRadiusProperty); + AffectsRender(ArrowSizeProperty, BorderWidthProperty, CornerRadiusProperty, BackgroundProperty, BorderBrushProperty); + } + + private Size RenderSize => Bounds.Size; + + public CornerRadius CornerRadius + { + get => GetValue(CornerRadiusProperty); + set => SetValue(CornerRadiusProperty, value); + } + + public IBrush Background + { + get => GetValue(BackgroundProperty); + set => SetValue(BackgroundProperty, value); + } + + public IBrush BorderBrush + { + get => GetValue(BorderBrushProperty); + set => SetValue(BorderBrushProperty, value); + } + + protected override Size MeasureOverride(Size constraint) + { + var width = 2d * BorderWidth + Padding.Left + Padding.Right; + var height = 2d * BorderWidth + Padding.Top + Padding.Bottom; + + if (Child != null) + { + Child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + width += Child.DesiredSize.Width; + height += Child.DesiredSize.Height; + } + + var minWidth = BorderWidth + Math.Max( + CornerRadius.TopLeft + CornerRadius.TopRight, + CornerRadius.BottomLeft + CornerRadius.BottomRight + ArrowSize.Width); + + var minHeight = BorderWidth + Math.Max( + CornerRadius.TopLeft + CornerRadius.BottomLeft, + CornerRadius.TopRight + CornerRadius.BottomRight); + + return new Size( + Math.Max(width, minWidth), + Math.Max(height, minHeight) + ArrowSize.Height); + } + + protected override Size ArrangeOverride(Size size) + { + if (Child != null) + { + Child.Arrange(new Rect( + BorderWidth + Padding.Left, + BorderWidth + Padding.Top, + size.Width - BorderWidth - Padding.Right, + size.Height - BorderWidth - Padding.Bottom)); + } + + return size; + } + + public override void Render(DrawingContext drawingContext) + { + var pen = new Pen + { + Brush = BorderBrush, + Thickness = BorderWidth, + LineJoin = PenLineJoin.Round + }; + + drawingContext.DrawGeometry(Background, pen, BuildGeometry()); + + base.Render(drawingContext); + } + } +} diff --git a/MapControl/Avalonia/Themes/Generic.axaml b/MapControl/Avalonia/Themes/Generic.axaml new file mode 100644 index 00000000..308630cc --- /dev/null +++ b/MapControl/Avalonia/Themes/Generic.axaml @@ -0,0 +1,49 @@ + + + + + + diff --git a/MapControl/Shared/MapPanel.cs b/MapControl/Shared/MapPanel.cs index 19dab542..6d5a1a9a 100644 --- a/MapControl/Shared/MapPanel.cs +++ b/MapControl/Shared/MapPanel.cs @@ -59,15 +59,14 @@ namespace MapControl private static readonly DependencyProperty ParentMapProperty = DependencyPropertyHelper.RegisterAttached("ParentMap", null, - (element, oldValue, newValue) => SetParentMap(element, newValue), true); - - private static void SetParentMap(FrameworkElement element, MapBase parentMap) - { - if (element is IMapElement mapElement) - { - mapElement.ParentMap = parentMap; - } - } + (element, oldValue, newValue) => + { + if (element is IMapElement mapElement) + { + mapElement.ParentMap = newValue; + } + }, + true); // inherits private MapBase parentMap; diff --git a/MapControl/Shared/PushpinBorder.cs b/MapControl/Shared/PushpinBorder.cs index 3097e607..34bcc72f 100644 --- a/MapControl/Shared/PushpinBorder.cs +++ b/MapControl/Shared/PushpinBorder.cs @@ -14,6 +14,9 @@ using Windows.UI.Xaml.Media; using Windows.Foundation; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media; +#elif AVALONIA +using Avalonia.Media; +using HorizontalAlignment = Avalonia.Layout.HorizontalAlignment; #endif namespace MapControl diff --git a/MapControl/WinUI/MapContentControl.WinUI.cs b/MapControl/WinUI/MapContentControl.WinUI.cs index 35f9104b..9b1d1c52 100644 --- a/MapControl/WinUI/MapContentControl.WinUI.cs +++ b/MapControl/WinUI/MapContentControl.WinUI.cs @@ -57,16 +57,16 @@ namespace MapControl if (parentMap != null) { + // Workaround for missing RelativeSource AncestorType=MapBase Bindings in default Style. + // if (Background == null) { SetBinding(BackgroundProperty, parentMap.CreateBinding(nameof(Background))); } - if (Foreground == null) { SetBinding(ForegroundProperty, parentMap.CreateBinding(nameof(Foreground))); } - if (BorderBrush == null) { SetBinding(BorderBrushProperty, parentMap.CreateBinding(nameof(Foreground))); diff --git a/MapControl/WinUI/MapItem.WinUI.cs b/MapControl/WinUI/MapItem.WinUI.cs index cd1a041b..b7f0f94e 100644 --- a/MapControl/WinUI/MapItem.WinUI.cs +++ b/MapControl/WinUI/MapItem.WinUI.cs @@ -23,13 +23,11 @@ namespace MapControl public static readonly DependencyProperty LocationProperty = DependencyPropertyHelper.Register(nameof(Location), null, - (item, oldValue, newValue) => item.LocationPropertyChanged(newValue)); - - private void LocationPropertyChanged(Location location) - { - MapPanel.SetLocation(this, location); - UpdateMapTransform(location); - } + (item, oldValue, newValue) => + { + MapPanel.SetLocation(item, newValue); + item.UpdateMapTransform(newValue); + }); public MapItem() { @@ -51,16 +49,16 @@ namespace MapControl if (parentMap != null) { + // Workaround for missing RelativeSource AncestorType=MapBase Bindings in default Style. + // if (Background == null) { SetBinding(BackgroundProperty, parentMap.CreateBinding(nameof(Background))); } - if (Foreground == null) { SetBinding(ForegroundProperty, parentMap.CreateBinding(nameof(Foreground))); } - if (BorderBrush == null) { SetBinding(BorderBrushProperty, parentMap.CreateBinding(nameof(Foreground))); diff --git a/SampleApps/AvaloniaApp/App.axaml b/SampleApps/AvaloniaApp/App.axaml index 1a489672..31770f23 100644 --- a/SampleApps/AvaloniaApp/App.axaml +++ b/SampleApps/AvaloniaApp/App.axaml @@ -4,5 +4,6 @@ RequestedThemeVariant="Default"> + diff --git a/SampleApps/AvaloniaApp/MainWindow.axaml b/SampleApps/AvaloniaApp/MainWindow.axaml index f94939f0..56ffaada 100644 --- a/SampleApps/AvaloniaApp/MainWindow.axaml +++ b/SampleApps/AvaloniaApp/MainWindow.axaml @@ -12,114 +12,116 @@ Center="53.5,8.2" DoubleTapped="OnMapDoubleTapped"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +