diff --git a/MapControl/Avalonia/MapPanel.Avalonia.cs b/MapControl/Avalonia/MapPanel.Avalonia.cs index f8c9fb37..d794ff5d 100644 --- a/MapControl/Avalonia/MapPanel.Avalonia.cs +++ b/MapControl/Avalonia/MapPanel.Avalonia.cs @@ -1,4 +1,6 @@ -namespace MapControl +using System.Collections.Generic; + +namespace MapControl { public partial class MapPanel { @@ -13,6 +15,16 @@ protected Controls ChildElements => Children; + protected FrameworkElement GetChildElement(int index) => index < Children.Count ? Children[index] : null; + + protected void InsertChildElement(int index, FrameworkElement element) => Children.Insert(index, element); + + protected void InsertChildElements(int index, IEnumerable elements) => Children.InsertRange(index, elements); + + protected void RemoveChildElement(int index) => Children.RemoveAt(index); + + protected void RemoveChildElements(int index, int count) => Children.RemoveRange(index, count); + static MapPanel() { AffectsParentArrange(LocationProperty, BoundingBoxProperty); diff --git a/MapControl/Shared/MapBase.MapLayer.cs b/MapControl/Shared/MapBase.MapLayer.cs index b0d75522..9eb48214 100644 --- a/MapControl/Shared/MapBase.MapLayer.cs +++ b/MapControl/Shared/MapBase.MapLayer.cs @@ -8,11 +8,9 @@ using System.Windows.Media; using System.Windows.Threading; #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; #endif @@ -26,8 +24,11 @@ namespace MapControl public partial class MapBase { + private bool hasMapLayerBackground; + private bool hasMapLayerForeground; + public static readonly DependencyProperty MapLayerProperty = - DependencyPropertyHelper.Register(nameof(MapLayer), null, + DependencyPropertyHelper.Register(nameof(MapLayer), null, (map, oldValue, newValue) => map.MapLayerPropertyChanged(oldValue, newValue)); public static readonly DependencyProperty MapLayerItemsSourceProperty = @@ -39,9 +40,9 @@ namespace MapControl /// If the layer implements IMapLayer (like MapTileLayer or MapImageLayer), its (non-null) MapBackground /// and MapForeground property values are used for the MapBase Background and Foreground properties. /// - public FrameworkElement MapLayer + public object MapLayer { - get => (FrameworkElement)GetValue(MapLayerProperty); + get => GetValue(MapLayerProperty); set => SetValue(MapLayerProperty, value); } @@ -51,44 +52,52 @@ namespace MapControl set => SetValue(MapLayerItemsSourceProperty, value); } - private void MapLayerPropertyChanged(FrameworkElement oldLayer, FrameworkElement newLayer) + private void MapLayerPropertyChanged(object oldLayer, object newLayer) { + var firstChild = GetChildElement(0); + if (oldLayer != null) { - if (Children.Count > 0 && Children[0] == oldLayer) + if (firstChild != null && + (firstChild == oldLayer as FrameworkElement || firstChild.DataContext == oldLayer)) { - Children.RemoveAt(0); + RemoveChildElement(0); } - if (oldLayer is IMapLayer mapLayer) + if (hasMapLayerBackground) { - if (mapLayer.MapBackground != null) - { - ClearValue(BackgroundProperty); - } - if (mapLayer.MapForeground != null) - { - ClearValue(ForegroundProperty); - } + ClearValue(BackgroundProperty); + } + + if (hasMapLayerForeground) + { + ClearValue(ForegroundProperty); } } + hasMapLayerBackground = false; + hasMapLayerForeground = false; + if (newLayer != null) { - if (Children.Count == 0 || Children[0] != newLayer) + if (firstChild == null || + firstChild != newLayer as FrameworkElement && firstChild.DataContext != newLayer) { - Children.Insert(0, newLayer); + InsertChildElement(0, GetMapLayer(newLayer)); } - if (newLayer is IMapLayer mapLayer) + if (GetChildElement(0) is IMapLayer mapLayer) { if (mapLayer.MapBackground != null) { Background = mapLayer.MapBackground; + hasMapLayerBackground = true; } + if (mapLayer.MapForeground != null) { Foreground = mapLayer.MapForeground; + hasMapLayerForeground = true; } } } @@ -144,31 +153,32 @@ namespace MapControl private void AddMapLayers(IEnumerable items, int index) { - var mapLayers = items.Cast().Select(CreateMapLayer).ToList(); + var mapLayers = items.Cast().Select(GetMapLayer).ToList(); + + if (mapLayers.Count > 0) + { #if WPF - // Execute at DispatcherPriority.DataBind to ensure that all bindings are evaluated. - Dispatcher.Invoke(() => AddMapLayers(mapLayers, index), DispatcherPriority.DataBind); + // Execute at DispatcherPriority.DataBind to ensure that all bindings are evaluated. + Dispatcher.Invoke(() => AddMapLayers(mapLayers, index), DispatcherPriority.DataBind); #else - AddMapLayers(mapLayers, index); + AddMapLayers(mapLayers, index); #endif + } } - private void AddMapLayers(IEnumerable mapLayers, int index) + private void AddMapLayers(List mapLayers, int index) { - foreach (var mapLayer in mapLayers) - { - Children.Insert(index, mapLayer); + InsertChildElements(index, mapLayers); - if (index++ == 0) - { - MapLayer = mapLayer; - } + if (index == 0) + { + MapLayer = mapLayers[0]; } } private void RemoveMapLayers(IEnumerable items, int index) { - Children.RemoveRange(index, items.Cast().Count()); + RemoveChildElements(index, items.Cast().Count()); if (index == 0) { @@ -176,7 +186,7 @@ namespace MapControl } } - private FrameworkElement CreateMapLayer(object item) + private FrameworkElement GetMapLayer(object item) { FrameworkElement mapLayer = null; @@ -185,7 +195,7 @@ namespace MapControl mapLayer = item as FrameworkElement ?? TryLoadDataTemplate(item); } - return mapLayer ?? new MapControl.MapPanel(); + return mapLayer ?? new MapTileLayer(); } private FrameworkElement TryLoadDataTemplate(object item) @@ -203,7 +213,7 @@ namespace MapControl element = (FrameworkElement)template.LoadContent(); } #else - if (this.TryFindResource(item.GetType().FullName) is DataTemplate template) + if (TryFindResource(this, item.GetType().FullName) is DataTemplate template) { element = (FrameworkElement)template.LoadContent(); } @@ -215,27 +225,16 @@ namespace MapControl return element; } - } #if UWP || WINUI - internal static class MapBaseExtensions - { - public static void RemoveRange(this UIElementCollection elements, int index, int count) - { - while (--count >= 0) + private static object TryFindResource(FrameworkElement element, object key) { - elements.RemoveAt(index); + return element.Resources.ContainsKey(key) + ? element.Resources[key] + : element.Parent is FrameworkElement parent + ? TryFindResource(parent, key) + : null; } - } - - public static object TryFindResource(this FrameworkElement element, object key) - { - return element.Resources.ContainsKey(key) - ? element.Resources[key] - : element.Parent is FrameworkElement parent - ? TryFindResource(parent, key) - : null; - } - } #endif + } } diff --git a/MapControl/WPF/MapPanel.WPF.cs b/MapControl/WPF/MapPanel.WPF.cs index fd7683fe..d3cfec0c 100644 --- a/MapControl/WPF/MapPanel.WPF.cs +++ b/MapControl/WPF/MapPanel.WPF.cs @@ -18,7 +18,23 @@ namespace MapControl DependencyPropertyHelper.RegisterAttached("BoundingBox", typeof(MapPanel), null, FrameworkPropertyMetadataOptions.AffectsParentArrange); - protected IEnumerable ChildElements => InternalChildren.OfType(); + protected IEnumerable ChildElements => Children.OfType(); + + protected FrameworkElement GetChildElement(int index) => index < Children.Count ? (FrameworkElement)Children[index] : null; + + protected void InsertChildElement(int index, FrameworkElement element) => Children.Insert(index, element); + + protected void InsertChildElements(int index, IEnumerable elements) + { + foreach (var element in elements) + { + Children.Insert(index++, element); + } + } + + protected void RemoveChildElement(int index) => Children.RemoveAt(index); + + protected void RemoveChildElements(int index, int count) => Children.RemoveRange(index, count); public static MapBase GetParentMap(FrameworkElement element) { diff --git a/MapControl/WinUI/MapPanel.WinUI.cs b/MapControl/WinUI/MapPanel.WinUI.cs index a6793a4b..18b9022e 100644 --- a/MapControl/WinUI/MapPanel.WinUI.cs +++ b/MapControl/WinUI/MapPanel.WinUI.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; using System.Linq; +using System.Xml.Linq; + #if UWP using Windows.UI.Xaml; using Windows.UI.Xaml.Media; @@ -25,6 +27,28 @@ namespace MapControl protected IEnumerable ChildElements => Children.OfType(); + protected FrameworkElement GetChildElement(int index) => index < Children.Count ? (FrameworkElement)Children[index] : null; + + protected void InsertChildElement(int index, FrameworkElement element) => Children.Insert(index, element); + + protected void InsertChildElements(int index, IEnumerable elements) + { + foreach (var element in elements) + { + Children.Insert(index++, element); + } + } + + protected void RemoveChildElement(int index) => Children.RemoveAt(index); + + protected void RemoveChildElements(int index, int count) + { + while (--count >= 0) + { + RemoveChildElement(index); + } + } + public static void InitMapElement(FrameworkElement element) { // Workaround for missing property value inheritance.