diff --git a/MapControl/Avalonia/MapPolypoint.Avalonia.cs b/MapControl/Avalonia/MapPolypoint.Avalonia.cs index fd538477..45dfe5f3 100644 --- a/MapControl/Avalonia/MapPolypoint.Avalonia.cs +++ b/MapControl/Avalonia/MapPolypoint.Avalonia.cs @@ -52,32 +52,49 @@ namespace MapControl protected void UpdateData(IEnumerable locations, bool closed) { - var pathFigures = new PathFigures(); + var figures = new PathFigures(); if (ParentMap != null && locations != null) { var longitudeOffset = GetLongitudeOffset(Location ?? locations.FirstOrDefault()); - AddPolylinePoints(pathFigures, locations, longitudeOffset, closed); + AddPolylinePoints(figures, locations, longitudeOffset, closed); } - SetPathFigures(pathFigures); + SetPathFigures(figures); } - protected void SetPathFigures(PathFigures pathFigures) + protected void UpdateData(IEnumerable> polygons) { - if (pathFigures.Count == 0) + var figures = new PathFigures(); + + if (ParentMap != null && polygons != null) + { + var longitudeOffset = GetLongitudeOffset(Location); + + foreach (var locations in polygons) + { + AddPolylinePoints(figures, locations, longitudeOffset, true); + } + } + + SetPathFigures(figures); + } + + protected void SetPathFigures(PathFigures figures) + { + if (figures.Count == 0) { // Avalonia Shape seems to ignore PathGeometry with empty Figures collection - pathFigures.Add(new PathFigure { StartPoint = new Point(-1000, -1000) }); + figures.Add(new PathFigure { StartPoint = new Point(-1000, -1000) }); } - ((PathGeometry)Data).Figures = pathFigures; + ((PathGeometry)Data).Figures = figures; InvalidateGeometry(); } - private void AddPolylinePoints(PathFigures pathFigures, IEnumerable locations, double longitudeOffset, bool closed) + private void AddPolylinePoints(PathFigures figures, IEnumerable locations, double longitudeOffset, bool closed) { var points = locations .Select(location => LocationToView(location, longitudeOffset)) @@ -86,14 +103,14 @@ namespace MapControl if (points.Any()) { - var startPoint = points.First(); - var polylineSegment = new PolyLineSegment(points.Skip(1)); - var minX = startPoint.X; - var maxX = startPoint.X; - var minY = startPoint.Y; - var maxY = startPoint.Y; + var start = points.First(); + var polyline = new PolyLineSegment(points.Skip(1)); + var minX = start.X; + var maxX = start.X; + var minY = start.Y; + var maxY = start.Y; - foreach (var point in polylineSegment.Points) + foreach (var point in polyline.Points) { minX = Math.Min(minX, point.X); maxX = Math.Max(maxX, point.X); @@ -104,15 +121,15 @@ namespace MapControl if (maxX >= 0 && minX <= ParentMap.ActualWidth && maxY >= 0 && minY <= ParentMap.ActualHeight) { - var pathFigure = new PathFigure + var figure = new PathFigure { - StartPoint = startPoint, + StartPoint = start, IsClosed = closed, IsFilled = true }; - pathFigure.Segments.Add(polylineSegment); - pathFigures.Add(pathFigure); + figure.Segments.Add(polyline); + figures.Add(figure); } } } diff --git a/MapControl/WPF/MapMultiPolygon.WPF.cs b/MapControl/Shared/MapMultiPolygon.cs similarity index 94% rename from MapControl/WPF/MapMultiPolygon.WPF.cs rename to MapControl/Shared/MapMultiPolygon.cs index fd9db3d6..da708ea5 100644 --- a/MapControl/WPF/MapMultiPolygon.WPF.cs +++ b/MapControl/Shared/MapMultiPolygon.cs @@ -3,7 +3,13 @@ // Licensed under the Microsoft Public License (Ms-PL) using System.Collections.Generic; +#if WPF using System.Windows; +#elif UWP +using Windows.UI.Xaml; +#elif WINUI +using Microsoft.UI.Xaml; +#endif namespace MapControl { diff --git a/MapControl/Shared/PolygonCollection.cs b/MapControl/Shared/PolygonCollection.cs new file mode 100644 index 00000000..1719addf --- /dev/null +++ b/MapControl/Shared/PolygonCollection.cs @@ -0,0 +1,70 @@ +// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control +// Copyright © 2024 Clemens Fischer +// Licensed under the Microsoft Public License (Ms-PL) + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; + +namespace MapControl +{ + /// + /// An ObservableCollection of IEnumerable of Location. PolygonCollection adds a CollectionChanged + /// listener to each element that implements INotifyCollectionChanged and, when such an element changes, + /// fires its own CollectionChanged event with NotifyCollectionChangedAction.Replace for that element. + /// + public class PolygonCollection : ObservableCollection> + { + private void PolygonChanged(object sender, NotifyCollectionChangedEventArgs e) + { + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender)); + } + + protected override void InsertItem(int index, IEnumerable polygon) + { + if (polygon is INotifyCollectionChanged addedPolygon) + { + addedPolygon.CollectionChanged += PolygonChanged; + } + + base.InsertItem(index, polygon); + } + + protected override void SetItem(int index, IEnumerable polygon) + { + if (this[index] is INotifyCollectionChanged removedPolygon) + { + removedPolygon.CollectionChanged -= PolygonChanged; + } + + if (polygon is INotifyCollectionChanged addedPolygon) + { + addedPolygon.CollectionChanged += PolygonChanged; + } + + base.SetItem(index, polygon); + } + + protected override void RemoveItem(int index) + { + if (this[index] is INotifyCollectionChanged removedPolygon) + { + removedPolygon.CollectionChanged -= PolygonChanged; + } + + base.RemoveItem(index); + } + + protected override void ClearItems() + { + foreach (var polygon in this.OfType()) + { + polygon.CollectionChanged -= PolygonChanged; + } + + base.ClearItems(); + } + } +} diff --git a/MapControl/UWP/MapControl.UWP.csproj b/MapControl/UWP/MapControl.UWP.csproj index edf6650e..24bf291b 100644 --- a/MapControl/UWP/MapControl.UWP.csproj +++ b/MapControl/UWP/MapControl.UWP.csproj @@ -113,6 +113,9 @@ MapItemsControl.cs + + MapMultiPolygon.cs + MapPanel.cs @@ -149,6 +152,9 @@ PolarStereographicProjection.cs + + PolygonCollection.cs + PushpinBorder.cs diff --git a/MapControl/WPF/MapControl.WPF.csproj b/MapControl/WPF/MapControl.WPF.csproj index d37afcd9..59656025 100644 --- a/MapControl/WPF/MapControl.WPF.csproj +++ b/MapControl/WPF/MapControl.WPF.csproj @@ -20,6 +20,10 @@ + + + + diff --git a/MapControl/WPF/MapPolypoint.WPF.cs b/MapControl/WPF/MapPolypoint.WPF.cs index f71c5bab..e52f68f4 100644 --- a/MapControl/WPF/MapPolypoint.WPF.cs +++ b/MapControl/WPF/MapPolypoint.WPF.cs @@ -77,9 +77,9 @@ namespace MapControl { var longitudeOffset = GetLongitudeOffset(Location); - foreach (var polygon in polygons) + foreach (var locations in polygons) { - AddPolylinePoints(context, polygon, longitudeOffset, true); + AddPolylinePoints(context, locations, longitudeOffset, true); } } } @@ -94,8 +94,27 @@ namespace MapControl if (points.Any()) { - context.BeginFigure(points.First(), true, closed); - context.PolyLineTo(points.Skip(1).ToList(), true, true); + var start = points.First(); + var polyline = points.Skip(1).ToList(); + var minX = start.X; + var maxX = start.X; + var minY = start.Y; + var maxY = start.Y; + + foreach (var point in polyline) + { + minX = Math.Min(minX, point.X); + maxX = Math.Max(maxX, point.X); + minY = Math.Min(minY, point.Y); + maxY = Math.Max(maxY, point.Y); + } + + if (maxX >= 0 && minX <= ParentMap.ActualWidth && + maxY >= 0 && minY <= ParentMap.ActualHeight) + { + context.BeginFigure(start, true, closed); + context.PolyLineTo(polyline, true, true); + } } } } diff --git a/MapControl/WPF/PolygonCollection.WPF.cs b/MapControl/WPF/PolygonCollection.WPF.cs index 29df4c47..c456e6c4 100644 --- a/MapControl/WPF/PolygonCollection.WPF.cs +++ b/MapControl/WPF/PolygonCollection.WPF.cs @@ -27,9 +27,9 @@ namespace MapControl protected override void InsertItem(int index, IEnumerable polygon) { - if (polygon is INotifyCollectionChanged observablePolygon) + if (polygon is INotifyCollectionChanged addedPolygon) { - CollectionChangedEventManager.AddListener(observablePolygon, this); + CollectionChangedEventManager.AddListener(addedPolygon, this); } base.InsertItem(index, polygon); @@ -37,9 +37,14 @@ namespace MapControl protected override void SetItem(int index, IEnumerable polygon) { - if (this[index] is INotifyCollectionChanged observablePolygon) + if (this[index] is INotifyCollectionChanged removedPolygon) { - CollectionChangedEventManager.RemoveListener(observablePolygon, this); + CollectionChangedEventManager.RemoveListener(removedPolygon, this); + } + + if (polygon is INotifyCollectionChanged addedPolygon) + { + CollectionChangedEventManager.AddListener(addedPolygon, this); } base.SetItem(index, polygon); @@ -47,9 +52,9 @@ namespace MapControl protected override void RemoveItem(int index) { - if (this[index] is INotifyCollectionChanged observablePolygon) + if (this[index] is INotifyCollectionChanged removedPolygon) { - CollectionChangedEventManager.RemoveListener(observablePolygon, this); + CollectionChangedEventManager.RemoveListener(removedPolygon, this); } base.RemoveItem(index); @@ -57,9 +62,9 @@ namespace MapControl protected override void ClearItems() { - foreach (var observablePolygon in this.OfType()) + foreach (var polygon in this.OfType()) { - CollectionChangedEventManager.RemoveListener(observablePolygon, this); + CollectionChangedEventManager.RemoveListener(polygon, this); } base.ClearItems(); diff --git a/MapControl/WinUI/MapPolypoint.WinUI.cs b/MapControl/WinUI/MapPolypoint.WinUI.cs index e7c3cf40..0adc96eb 100644 --- a/MapControl/WinUI/MapPolypoint.WinUI.cs +++ b/MapControl/WinUI/MapPolypoint.WinUI.cs @@ -59,18 +59,34 @@ namespace MapControl protected void UpdateData(IEnumerable locations, bool closed) { - var pathFigures = ((PathGeometry)Data).Figures; - pathFigures.Clear(); + var figures = ((PathGeometry)Data).Figures; + figures.Clear(); if (ParentMap != null && locations != null) { var longitudeOffset = GetLongitudeOffset(Location ?? locations.FirstOrDefault()); - AddPolylinePoints(pathFigures, locations, longitudeOffset, closed); + AddPolylinePoints(figures, locations, longitudeOffset, closed); } } - private void AddPolylinePoints(PathFigureCollection pathFigures, IEnumerable locations, double longitudeOffset, bool closed) + protected void UpdateData(IEnumerable> polygons) + { + var figures = ((PathGeometry)Data).Figures; + figures.Clear(); + + if (ParentMap != null && polygons != null) + { + var longitudeOffset = GetLongitudeOffset(Location); + + foreach (var locations in polygons) + { + AddPolylinePoints(figures, locations, longitudeOffset, true); + } + } + } + + private void AddPolylinePoints(PathFigureCollection figures, IEnumerable locations, double longitudeOffset, bool closed) { var points = locations .Select(location => LocationToView(location, longitudeOffset)) @@ -79,16 +95,16 @@ namespace MapControl if (points.Any()) { - var startPoint = points.First(); - var polylineSegment = new PolyLineSegment(); - var minX = startPoint.X; - var maxX = startPoint.X; - var minY = startPoint.Y; - var maxY = startPoint.Y; + var start = points.First(); + var polyline = new PolyLineSegment(); + var minX = start.X; + var maxX = start.X; + var minY = start.Y; + var maxY = start.Y; foreach (var point in points.Skip(1)) { - polylineSegment.Points.Add(point); + polyline.Points.Add(point); minX = Math.Min(minX, point.X); maxX = Math.Max(maxX, point.X); minY = Math.Min(minY, point.Y); @@ -98,15 +114,15 @@ namespace MapControl if (maxX >= 0 && minX <= ParentMap.ActualWidth && maxY >= 0 && minY <= ParentMap.ActualHeight) { - var pathFigure = new PathFigure + var figure = new PathFigure { - StartPoint = startPoint, + StartPoint = start, IsClosed = closed, IsFilled = true }; - pathFigure.Segments.Add(polylineSegment); - pathFigures.Add(pathFigure); + figure.Segments.Add(polyline); + figures.Add(figure); } } } diff --git a/SampleApps/AvaloniaApp/MainWindow.axaml b/SampleApps/AvaloniaApp/MainWindow.axaml index 5b5f6b5f..47832b0c 100644 --- a/SampleApps/AvaloniaApp/MainWindow.axaml +++ b/SampleApps/AvaloniaApp/MainWindow.axaml @@ -85,17 +85,20 @@ - + - - - 53.45,8.1 53.45,8.3 53.55,8.3 53.55,8.1 - - + + + + 53.45,8.1 53.45,8.3 53.55,8.3 53.55,8.1 + 53.47,8.14 53.47,8.26 53.53,8.26 53.53,8.14 + + + diff --git a/SampleApps/WinUiApp/MainWindow.xaml b/SampleApps/WinUiApp/MainWindow.xaml index 4ccf463e..051a8f1b 100644 --- a/SampleApps/WinUiApp/MainWindow.xaml +++ b/SampleApps/WinUiApp/MainWindow.xaml @@ -174,17 +174,20 @@ SelectionChanged="MapItemsControlSelectionChanged" DoubleTapped="MapItemsControlDoubleTapped"/> - + - - - 53.45,8.1 53.45,8.3 53.55,8.3 53.55,8.1 - - + + + + 53.45,8.1 53.45,8.3 53.55,8.3 53.55,8.1 + 53.47,8.14 53.47,8.26 53.53,8.26 53.53,8.14 + + + diff --git a/SampleApps/WpfApplication/MainWindow.xaml b/SampleApps/WpfApplication/MainWindow.xaml index 41d9c903..00a2a173 100644 --- a/SampleApps/WpfApplication/MainWindow.xaml +++ b/SampleApps/WpfApplication/MainWindow.xaml @@ -145,14 +145,21 @@ - - - + + + + + 53.45,8.1 53.45,8.3 53.55,8.3 53.55,8.1 + 53.47,8.14 53.47,8.26 53.53,8.26 53.53,8.14 + + + +