From 7cfb80520b6580b917a92c0dc021ff8b6f5a1bc6 Mon Sep 17 00:00:00 2001 From: ClemensFischer Date: Mon, 2 Feb 2026 12:10:09 +0100 Subject: [PATCH] Updated MapContentControl, MapItem, MapPath --- .../DependencyPropertyHelper.Avalonia.cs | 23 ++++++++ MapControl/Avalonia/MapBase.Avalonia.cs | 2 +- .../Avalonia/MapContentControl.Avalonia.cs | 42 +++++++++++++++ MapControl/Avalonia/MapGraticule.Avalonia.cs | 6 +-- MapControl/Avalonia/MapItem.Avalonia.cs | 10 +++- MapControl/Avalonia/MapPath.Avalonia.cs | 21 ++------ MapControl/Shared/MapContentControl.cs | 54 ------------------- MapControl/Shared/MapItem.cs | 15 ------ MapControl/Shared/MapPath.cs | 20 +++++++ .../WPF/DependencyPropertyHelper.WPF.cs | 21 ++++++++ MapControl/WPF/MapBase.WPF.cs | 2 +- MapControl/WPF/MapContentControl.WPF.cs | 35 +++++++++++- MapControl/WPF/MapGraticule.WPF.cs | 6 +-- MapControl/WPF/MapItem.WPF.cs | 7 +++ MapControl/WPF/MapPath.WPF.cs | 26 +++------ MapControl/WinUI/MapContentControl.WinUI.cs | 33 +++++++++++- MapControl/WinUI/MapItem.WinUI.cs | 12 +++++ MapControl/WinUI/MapPath.WinUI.cs | 14 ----- 18 files changed, 216 insertions(+), 133 deletions(-) create mode 100644 MapControl/Avalonia/MapContentControl.Avalonia.cs delete mode 100644 MapControl/Shared/MapContentControl.cs diff --git a/MapControl/Avalonia/DependencyPropertyHelper.Avalonia.cs b/MapControl/Avalonia/DependencyPropertyHelper.Avalonia.cs index 7804d31a..bbb1c621 100644 --- a/MapControl/Avalonia/DependencyPropertyHelper.Avalonia.cs +++ b/MapControl/Avalonia/DependencyPropertyHelper.Avalonia.cs @@ -56,6 +56,29 @@ namespace MapControl return property; } + public static StyledProperty AddOwner( + StyledProperty source) where TOwner : AvaloniaObject + { + return source.AddOwner(); + } + + public static StyledProperty AddOwner( + StyledProperty source, + TValue defaultValue) where TOwner : AvaloniaObject + { + return source.AddOwner(new StyledPropertyMetadata(new Optional(defaultValue))); + } + + public static StyledProperty AddOwner( + StyledProperty source, + Action changed) where TOwner : AvaloniaObject + { + var property = source.AddOwner(); + property.Changed.AddClassHandler((o, e) => changed(o, e.OldValue.Value, e.NewValue.Value)); + + return property; + } + public static void SetBinding(this AvaloniaObject target, AvaloniaProperty property, Binding binding) { target.Bind(property, binding); diff --git a/MapControl/Avalonia/MapBase.Avalonia.cs b/MapControl/Avalonia/MapBase.Avalonia.cs index d677d83a..2e9ac38a 100644 --- a/MapControl/Avalonia/MapBase.Avalonia.cs +++ b/MapControl/Avalonia/MapBase.Avalonia.cs @@ -15,7 +15,7 @@ namespace MapControl public partial class MapBase { public static readonly StyledProperty ForegroundProperty = - TextElement.ForegroundProperty.AddOwner(new StyledPropertyMetadata(new Optional(Brushes.Black))); + DependencyPropertyHelper.AddOwner(TextElement.ForegroundProperty, Brushes.Black); public static readonly StyledProperty AnimationEasingProperty = DependencyPropertyHelper.Register(nameof(AnimationEasing), new QuadraticEaseOut()); diff --git a/MapControl/Avalonia/MapContentControl.Avalonia.cs b/MapControl/Avalonia/MapContentControl.Avalonia.cs new file mode 100644 index 00000000..9350bdf8 --- /dev/null +++ b/MapControl/Avalonia/MapContentControl.Avalonia.cs @@ -0,0 +1,42 @@ +using Avalonia; +using Avalonia.Controls; + +namespace MapControl +{ + /// + /// ContentControl placed on a MapPanel at a geographic location specified by the Location property. + /// + public class MapContentControl : ContentControl + { + public static readonly StyledProperty LocationProperty = + DependencyPropertyHelper.AddOwner(MapPanel.LocationProperty); + + public static readonly StyledProperty AutoCollapseProperty = + DependencyPropertyHelper.AddOwner(MapPanel.AutoCollapseProperty); + + /// + /// Gets/sets MapPanel.Location. + /// + public Location Location + { + get => GetValue(LocationProperty); + set => SetValue(LocationProperty, value); + } + + /// + /// Gets/sets MapPanel.AutoCollapse. + /// + public bool AutoCollapse + { + get => GetValue(AutoCollapseProperty); + set => SetValue(AutoCollapseProperty, value); + } + } + + /// + /// MapContentControl with a Pushpin Style. + /// + public class Pushpin : MapContentControl + { + } +} diff --git a/MapControl/Avalonia/MapGraticule.Avalonia.cs b/MapControl/Avalonia/MapGraticule.Avalonia.cs index c8aeeb35..cc9ed745 100644 --- a/MapControl/Avalonia/MapGraticule.Avalonia.cs +++ b/MapControl/Avalonia/MapGraticule.Avalonia.cs @@ -15,13 +15,13 @@ namespace MapControl } public static readonly StyledProperty ForegroundProperty = - TextElement.ForegroundProperty.AddOwner(); + DependencyPropertyHelper.AddOwner(TextElement.ForegroundProperty); public static readonly StyledProperty FontFamilyProperty = - TextElement.FontFamilyProperty.AddOwner(); + DependencyPropertyHelper.AddOwner(TextElement.FontFamilyProperty); public static readonly StyledProperty FontSizeProperty = - TextElement.FontSizeProperty.AddOwner(new StyledPropertyMetadata(12d)); + DependencyPropertyHelper.AddOwner(TextElement.FontSizeProperty, 12d); /// /// Implements IMapElement.ParentMap. diff --git a/MapControl/Avalonia/MapItem.Avalonia.cs b/MapControl/Avalonia/MapItem.Avalonia.cs index f30774cc..30ba4902 100644 --- a/MapControl/Avalonia/MapItem.Avalonia.cs +++ b/MapControl/Avalonia/MapItem.Avalonia.cs @@ -1,10 +1,18 @@ -using Avalonia.Controls; +using Avalonia; +using Avalonia.Controls; using Avalonia.Input; namespace MapControl { public partial class MapItem { + public static readonly StyledProperty LocationProperty = + DependencyPropertyHelper.AddOwner(MapPanel.LocationProperty, + (item, oldValue, newValue) => item.UpdateMapTransform()); + + public static readonly StyledProperty AutoCollapseProperty = + DependencyPropertyHelper.AddOwner(MapPanel.AutoCollapseProperty); + protected override void OnPointerPressed(PointerPressedEventArgs e) { if (e.Pointer.Type != PointerType.Mouse && diff --git a/MapControl/Avalonia/MapPath.Avalonia.cs b/MapControl/Avalonia/MapPath.Avalonia.cs index 8599546b..951b6b3a 100644 --- a/MapControl/Avalonia/MapPath.Avalonia.cs +++ b/MapControl/Avalonia/MapPath.Avalonia.cs @@ -6,12 +6,9 @@ namespace MapControl { public partial class MapPath : Shape { - public static readonly StyledProperty DataProperty = Path.DataProperty.AddOwner(); - - static MapPath() - { - DataProperty.Changed.AddClassHandler((path, e) => path.UpdateData()); - } + public static readonly StyledProperty DataProperty = + DependencyPropertyHelper.AddOwner(Path.DataProperty, + (path, oldValue, newValue) => path.UpdateData()); public Geometry Data { @@ -20,17 +17,5 @@ namespace MapControl } protected override Geometry CreateDefiningGeometry() => Data; - - private void SetDataTransform(Matrix matrix) - { - if (Data.Transform is MatrixTransform transform) - { - transform.Matrix = matrix; - } - else - { - Data.Transform = new MatrixTransform(matrix); - } - } } } diff --git a/MapControl/Shared/MapContentControl.cs b/MapControl/Shared/MapContentControl.cs deleted file mode 100644 index bf5616b0..00000000 --- a/MapControl/Shared/MapContentControl.cs +++ /dev/null @@ -1,54 +0,0 @@ -#if WPF -using System.Windows; -using System.Windows.Controls; -#elif UWP -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -#elif WINUI -using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Controls; -#elif AVALONIA -using Avalonia.Controls; -#endif - -namespace MapControl -{ - /// - /// ContentControl placed on a MapPanel at a geographic location specified by the Location property. - /// - public partial class MapContentControl : ContentControl - { - public static readonly DependencyProperty LocationProperty = - DependencyPropertyHelper.Register(nameof(Location), null, - (control, oldValue, newValue) => MapPanel.SetLocation(control, newValue)); - - public static readonly DependencyProperty AutoCollapseProperty = - DependencyPropertyHelper.Register(nameof(AutoCollapse), false, - (control, oldValue, newValue) => MapPanel.SetAutoCollapse(control, newValue)); - - /// - /// Gets/sets MapPanel.Location. - /// - public Location Location - { - get => (Location)GetValue(LocationProperty); - set => SetValue(LocationProperty, value); - } - - /// - /// Gets/sets MapPanel.AutoCollapse. - /// - public bool AutoCollapse - { - get => (bool)GetValue(AutoCollapseProperty); - set => SetValue(AutoCollapseProperty, value); - } - } - - /// - /// MapContentControl with a Pushpin Style. - /// - public partial class Pushpin : MapContentControl - { - } -} diff --git a/MapControl/Shared/MapItem.cs b/MapControl/Shared/MapItem.cs index d961f831..6f456a28 100644 --- a/MapControl/Shared/MapItem.cs +++ b/MapControl/Shared/MapItem.cs @@ -1,13 +1,10 @@ #if WPF -using System.Windows; using System.Windows.Controls; using System.Windows.Media; #elif UWP -using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; #elif WINUI -using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media; #elif AVALONIA @@ -22,18 +19,6 @@ namespace MapControl /// public partial class MapItem : ListBoxItem, IMapElement { - public static readonly DependencyProperty LocationProperty = - DependencyPropertyHelper.Register(nameof(Location), null, - (item, oldValue, newValue) => - { - MapPanel.SetLocation(item, newValue); - item.UpdateMapTransform(); - }); - - public static readonly DependencyProperty AutoCollapseProperty = - DependencyPropertyHelper.Register(nameof(AutoCollapse), false, - (item, oldValue, newValue) => MapPanel.SetAutoCollapse(item, newValue)); - /// /// Gets/sets MapPanel.Location. /// diff --git a/MapControl/Shared/MapPath.cs b/MapControl/Shared/MapPath.cs index 2e2b5519..80c60a50 100644 --- a/MapControl/Shared/MapPath.cs +++ b/MapControl/Shared/MapPath.cs @@ -1,11 +1,15 @@ #if WPF using System.Windows; +using System.Windows.Media; #elif UWP using Windows.UI.Xaml; +using Windows.UI.Xaml.Media; #elif WINUI using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Media; #elif AVALONIA using Avalonia; +using Avalonia.Media; #endif namespace MapControl @@ -62,6 +66,22 @@ namespace MapControl UpdateData(); } + protected void SetDataTransform(Matrix matrix) + { + if (Data.Transform is MatrixTransform transform +#if WPF + && !transform.IsFrozen +#endif + ) + { + transform.Matrix = matrix; + } + else + { + Data.Transform = new MatrixTransform { Matrix = matrix }; + } + } + protected virtual void UpdateData() { if (Data != null && ParentMap != null && Location != null) diff --git a/MapControl/WPF/DependencyPropertyHelper.WPF.cs b/MapControl/WPF/DependencyPropertyHelper.WPF.cs index 73fbaa9d..e3d5c0cb 100644 --- a/MapControl/WPF/DependencyPropertyHelper.WPF.cs +++ b/MapControl/WPF/DependencyPropertyHelper.WPF.cs @@ -88,5 +88,26 @@ namespace MapControl { return DependencyProperty.RegisterReadOnly(name, typeof(TValue), typeof(TOwner), new PropertyMetadata(defaultValue)); } + + public static DependencyProperty AddOwner( + DependencyProperty source) where TOwner : DependencyObject + { + return source.AddOwner(typeof(TOwner)); + } + + public static DependencyProperty AddOwner( + DependencyProperty source, + TValue defaultValue) where TOwner : DependencyObject + { + return source.AddOwner(typeof(TOwner), new FrameworkPropertyMetadata(defaultValue)); + } + + public static DependencyProperty AddOwner( + DependencyProperty source, + Action changed = null) where TOwner : DependencyObject + { + return source.AddOwner(typeof(TOwner), new FrameworkPropertyMetadata( + (o, e) => changed((TOwner)o, (TValue)e.OldValue, (TValue)e.NewValue))); + } } } diff --git a/MapControl/WPF/MapBase.WPF.cs b/MapControl/WPF/MapBase.WPF.cs index 2ed01030..c400e700 100644 --- a/MapControl/WPF/MapBase.WPF.cs +++ b/MapControl/WPF/MapBase.WPF.cs @@ -8,7 +8,7 @@ namespace MapControl public partial class MapBase { public static readonly DependencyProperty ForegroundProperty = - TextElement.ForegroundProperty.AddOwner(typeof(MapBase), new FrameworkPropertyMetadata(Brushes.Black)); + DependencyPropertyHelper.AddOwner(TextElement.ForegroundProperty, Brushes.Black); public static readonly DependencyProperty AnimationEasingFunctionProperty = DependencyPropertyHelper.Register(nameof(AnimationEasingFunction), diff --git a/MapControl/WPF/MapContentControl.WPF.cs b/MapControl/WPF/MapContentControl.WPF.cs index be911d1a..4bc62e85 100644 --- a/MapControl/WPF/MapContentControl.WPF.cs +++ b/MapControl/WPF/MapContentControl.WPF.cs @@ -1,16 +1,47 @@ using System.Windows; +using System.Windows.Controls; namespace MapControl { - public partial class MapContentControl + /// + /// ContentControl placed on a MapPanel at a geographic location specified by the Location property. + /// + public class MapContentControl : ContentControl { + public static readonly DependencyProperty LocationProperty = + DependencyPropertyHelper.AddOwner(MapPanel.LocationProperty); + + public static readonly DependencyProperty AutoCollapseProperty = + DependencyPropertyHelper.AddOwner(MapPanel.AutoCollapseProperty); + + /// + /// Gets/sets MapPanel.Location. + /// + public Location Location + { + get => (Location)GetValue(LocationProperty); + set => SetValue(LocationProperty, value); + } + + /// + /// Gets/sets MapPanel.AutoCollapse. + /// + public bool AutoCollapse + { + get => (bool)GetValue(AutoCollapseProperty); + set => SetValue(AutoCollapseProperty, value); + } + static MapContentControl() { DefaultStyleKeyProperty.OverrideMetadata(typeof(MapContentControl), new FrameworkPropertyMetadata(typeof(MapContentControl))); } } - public partial class Pushpin + /// + /// MapContentControl with a Pushpin Style. + /// + public class Pushpin : MapContentControl { static Pushpin() { diff --git a/MapControl/WPF/MapGraticule.WPF.cs b/MapControl/WPF/MapGraticule.WPF.cs index 9cfff738..61389bc7 100644 --- a/MapControl/WPF/MapGraticule.WPF.cs +++ b/MapControl/WPF/MapGraticule.WPF.cs @@ -9,13 +9,13 @@ namespace MapControl public partial class MapGraticule : FrameworkElement, IMapElement { public static readonly DependencyProperty ForegroundProperty = - TextElement.ForegroundProperty.AddOwner(typeof(MapGraticule)); + DependencyPropertyHelper.AddOwner(TextElement.ForegroundProperty); public static readonly DependencyProperty FontFamilyProperty = - TextElement.FontFamilyProperty.AddOwner(typeof(MapGraticule)); + DependencyPropertyHelper.AddOwner(TextElement.FontFamilyProperty); public static readonly DependencyProperty FontSizeProperty = - TextElement.FontSizeProperty.AddOwner(typeof(MapGraticule), new FrameworkPropertyMetadata(12d)); + DependencyPropertyHelper.AddOwner(TextElement.FontSizeProperty, 12d); /// /// Implements IMapElement.ParentMap. diff --git a/MapControl/WPF/MapItem.WPF.cs b/MapControl/WPF/MapItem.WPF.cs index 75444644..eda7b2e1 100644 --- a/MapControl/WPF/MapItem.WPF.cs +++ b/MapControl/WPF/MapItem.WPF.cs @@ -6,6 +6,13 @@ namespace MapControl { public partial class MapItem { + public static readonly DependencyProperty LocationProperty = + DependencyPropertyHelper.AddOwner(MapPanel.LocationProperty, + (item, oldValue, newValue) => item.UpdateMapTransform()); + + public static readonly DependencyProperty AutoCollapseProperty = + DependencyPropertyHelper.AddOwner(MapPanel.AutoCollapseProperty); + static MapItem() { DefaultStyleKeyProperty.OverrideMetadata(typeof(MapItem), new FrameworkPropertyMetadata(typeof(MapItem))); diff --git a/MapControl/WPF/MapPath.WPF.cs b/MapControl/WPF/MapPath.WPF.cs index a022d594..5b9c0ea4 100644 --- a/MapControl/WPF/MapPath.WPF.cs +++ b/MapControl/WPF/MapPath.WPF.cs @@ -7,8 +7,8 @@ namespace MapControl public partial class MapPath : Shape { public static readonly DependencyProperty DataProperty = - Path.DataProperty.AddOwner(typeof(MapPath), - new FrameworkPropertyMetadata(null, (o, e) => ((MapPath)o).DataPropertyChanged(e))); + DependencyPropertyHelper.AddOwner(Path.DataProperty, + (path, oldValue, newValue) => path.DataPropertyChanged(oldValue, newValue)); public Geometry Data { @@ -18,29 +18,15 @@ namespace MapControl protected override Geometry DefiningGeometry => Data; - protected void SetDataTransform(Matrix matrix) - { - if (Data.Transform is MatrixTransform transform && !transform.IsFrozen) - { - transform.Matrix = matrix; - } - else - { - Data.Transform = new MatrixTransform(matrix); - } - } - - private void DataPropertyChanged(DependencyPropertyChangedEventArgs e) + private void DataPropertyChanged(Geometry oldValue, Geometry newValue) { // Check if Data is actually a new Geometry. // - if (e.NewValue != null && !ReferenceEquals(e.NewValue, e.OldValue)) + if (newValue != null && !ReferenceEquals(newValue, oldValue)) { - var data = (Geometry)e.NewValue; - - if (data.IsFrozen) + if (newValue.IsFrozen) { - Data = data.Clone(); // DataPropertyChanged called again + Data = newValue.Clone(); // DataPropertyChanged called again } else { diff --git a/MapControl/WinUI/MapContentControl.WinUI.cs b/MapControl/WinUI/MapContentControl.WinUI.cs index 02fd43cd..19af4a68 100644 --- a/MapControl/WinUI/MapContentControl.WinUI.cs +++ b/MapControl/WinUI/MapContentControl.WinUI.cs @@ -1,15 +1,43 @@ #if UWP using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Data; #else using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Data; #endif namespace MapControl { - public partial class MapContentControl + public partial class MapContentControl : ContentControl { + public static readonly DependencyProperty LocationProperty = + DependencyPropertyHelper.Register(nameof(Location), null, + (control, oldValue, newValue) => MapPanel.SetLocation(control, newValue)); + + public static readonly DependencyProperty AutoCollapseProperty = + DependencyPropertyHelper.Register(nameof(AutoCollapse), false, + (control, oldValue, newValue) => MapPanel.SetAutoCollapse(control, newValue)); + + /// + /// Gets/sets MapPanel.Location. + /// + public Location Location + { + get => (Location)GetValue(LocationProperty); + set => SetValue(LocationProperty, value); + } + + /// + /// Gets/sets MapPanel.AutoCollapse. + /// + public bool AutoCollapse + { + get => (bool)GetValue(AutoCollapseProperty); + set => SetValue(AutoCollapseProperty, value); + } + public MapContentControl() { DefaultStyleKey = typeof(MapContentControl); @@ -45,6 +73,9 @@ namespace MapControl } } + /// + /// MapContentControl with a Pushpin Style. + /// public partial class Pushpin : MapContentControl { public Pushpin() diff --git a/MapControl/WinUI/MapItem.WinUI.cs b/MapControl/WinUI/MapItem.WinUI.cs index d99928dc..f027598f 100644 --- a/MapControl/WinUI/MapItem.WinUI.cs +++ b/MapControl/WinUI/MapItem.WinUI.cs @@ -16,6 +16,18 @@ namespace MapControl { public partial class MapItem { + public static readonly DependencyProperty LocationProperty = + DependencyPropertyHelper.Register(nameof(Location), null, + (item, oldValue, newValue) => + { + MapPanel.SetLocation(item, newValue); + item.UpdateMapTransform(); + }); + + public static readonly DependencyProperty AutoCollapseProperty = + DependencyPropertyHelper.Register(nameof(AutoCollapse), false, + (item, oldValue, newValue) => MapPanel.SetAutoCollapse(item, newValue)); + private Windows.Foundation.Point? pointerPressedPosition; public MapItem() diff --git a/MapControl/WinUI/MapPath.WinUI.cs b/MapControl/WinUI/MapPath.WinUI.cs index c916969c..b1624814 100644 --- a/MapControl/WinUI/MapPath.WinUI.cs +++ b/MapControl/WinUI/MapPath.WinUI.cs @@ -1,8 +1,6 @@ #if UWP -using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Shapes; #else -using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Shapes; #endif @@ -14,17 +12,5 @@ namespace MapControl { MapPanel.InitMapElement(this); } - - private void SetDataTransform(Matrix matrix) - { - if (Data.Transform is MatrixTransform transform) - { - transform.Matrix = matrix; - } - else - { - Data.Transform = new MatrixTransform { Matrix = matrix }; - } - } } }