2022-01-11 19:42:12 +01:00
|
|
|
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
2024-02-03 21:01:53 +01:00
|
|
|
|
// Copyright © 2024 Clemens Fischer
|
2022-01-11 19:42:12 +01:00
|
|
|
|
// Licensed under the Microsoft Public License (Ms-PL)
|
|
|
|
|
|
|
2022-12-08 17:50:03 +01:00
|
|
|
|
using System;
|
2022-01-13 20:12:49 +01:00
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
|
using System.Collections.Specialized;
|
2021-12-05 17:16:14 +01:00
|
|
|
|
using System.Linq;
|
2024-05-22 11:25:32 +02:00
|
|
|
|
#if WPF
|
|
|
|
|
|
using System.Windows;
|
|
|
|
|
|
using System.Windows.Markup;
|
2021-12-05 17:16:14 +01:00
|
|
|
|
#elif UWP
|
|
|
|
|
|
using Windows.UI.Xaml;
|
2022-01-13 20:12:49 +01:00
|
|
|
|
using Windows.UI.Xaml.Markup;
|
2024-05-22 11:25:32 +02:00
|
|
|
|
#elif WINUI
|
|
|
|
|
|
using Microsoft.UI.Xaml;
|
|
|
|
|
|
using Microsoft.UI.Xaml.Markup;
|
2024-05-24 15:15:29 +02:00
|
|
|
|
#elif AVALONIA
|
|
|
|
|
|
using Avalonia.Interactivity;
|
|
|
|
|
|
using Avalonia.Metadata;
|
|
|
|
|
|
using DependencyProperty = Avalonia.AvaloniaProperty;
|
|
|
|
|
|
using FrameworkElement = Avalonia.Controls.Control;
|
2021-12-05 17:16:14 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
|
2022-01-11 19:42:12 +01:00
|
|
|
|
namespace MapControl.UiTools
|
2021-12-05 17:16:14 +01:00
|
|
|
|
{
|
2024-05-22 11:25:32 +02:00
|
|
|
|
#if WPF
|
2022-01-13 20:12:49 +01:00
|
|
|
|
[ContentProperty(nameof(Layer))]
|
2024-05-24 15:15:29 +02:00
|
|
|
|
#elif UWP || WINUI
|
2024-05-22 11:25:32 +02:00
|
|
|
|
[ContentProperty(Name = nameof(Layer))]
|
2022-01-13 20:12:49 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
public class MapLayerItem
|
|
|
|
|
|
{
|
2024-05-24 15:15:29 +02:00
|
|
|
|
#if AVALONIA
|
|
|
|
|
|
[Content]
|
|
|
|
|
|
#endif
|
|
|
|
|
|
public FrameworkElement Layer { get; set; }
|
|
|
|
|
|
|
2022-01-13 20:12:49 +01:00
|
|
|
|
public string Text { get; set; }
|
2022-12-08 17:50:03 +01:00
|
|
|
|
|
2024-05-24 15:15:29 +02:00
|
|
|
|
public Func<FrameworkElement> LayerFactory { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public FrameworkElement GetLayer() => Layer ?? (Layer = LayerFactory?.Invoke());
|
2022-01-13 20:12:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-22 11:25:32 +02:00
|
|
|
|
#if WPF
|
2022-01-13 20:12:49 +01:00
|
|
|
|
[ContentProperty(nameof(MapLayers))]
|
2024-05-24 15:15:29 +02:00
|
|
|
|
#elif UWP || WINUI
|
2024-05-22 11:25:32 +02:00
|
|
|
|
[ContentProperty(Name = nameof(MapLayers))]
|
2022-01-13 20:12:49 +01:00
|
|
|
|
#endif
|
2021-12-05 17:16:14 +01:00
|
|
|
|
public class MapLayersMenuButton : MenuButton
|
|
|
|
|
|
{
|
2024-05-24 15:15:29 +02:00
|
|
|
|
private FrameworkElement selectedLayer;
|
2022-01-21 18:37:05 +01:00
|
|
|
|
|
2021-12-05 17:16:14 +01:00
|
|
|
|
public MapLayersMenuButton()
|
2022-01-11 19:42:12 +01:00
|
|
|
|
: base("\uE81E")
|
2021-12-05 17:16:14 +01:00
|
|
|
|
{
|
2022-01-13 20:12:49 +01:00
|
|
|
|
((INotifyCollectionChanged)MapLayers).CollectionChanged += (s, e) => InitializeMenu();
|
|
|
|
|
|
((INotifyCollectionChanged)MapOverlays).CollectionChanged += (s, e) => InitializeMenu();
|
2021-12-05 17:16:14 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-23 18:08:14 +02:00
|
|
|
|
public static readonly DependencyProperty MapProperty =
|
2024-05-23 19:21:28 +02:00
|
|
|
|
DependencyPropertyHelper.Register<MapLayersMenuButton, MapBase>(nameof(Map), null,
|
2024-05-23 18:08:14 +02:00
|
|
|
|
(button, oldValue, newValue) => button.InitializeMenu());
|
2021-12-05 17:16:14 +01:00
|
|
|
|
|
|
|
|
|
|
public MapBase Map
|
|
|
|
|
|
{
|
2022-08-06 11:04:49 +02:00
|
|
|
|
get => (MapBase)GetValue(MapProperty);
|
|
|
|
|
|
set => SetValue(MapProperty, value);
|
2021-12-05 17:16:14 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-24 15:15:29 +02:00
|
|
|
|
#if AVALONIA
|
|
|
|
|
|
[Content]
|
|
|
|
|
|
#endif
|
2022-01-13 20:12:49 +01:00
|
|
|
|
public Collection<MapLayerItem> MapLayers { get; } = new ObservableCollection<MapLayerItem>();
|
2021-12-05 17:16:14 +01:00
|
|
|
|
|
2022-01-13 20:12:49 +01:00
|
|
|
|
public Collection<MapLayerItem> MapOverlays { get; } = new ObservableCollection<MapLayerItem>();
|
2021-12-05 17:16:14 +01:00
|
|
|
|
|
|
|
|
|
|
private void InitializeMenu()
|
|
|
|
|
|
{
|
2022-01-13 20:12:49 +01:00
|
|
|
|
if (Map != null)
|
2021-12-05 17:16:14 +01:00
|
|
|
|
{
|
|
|
|
|
|
var menu = CreateMenu();
|
|
|
|
|
|
|
2022-01-13 20:12:49 +01:00
|
|
|
|
foreach (var item in MapLayers)
|
2021-12-05 17:16:14 +01:00
|
|
|
|
{
|
2022-12-08 17:50:03 +01:00
|
|
|
|
menu.Items.Add(CreateMenuItem(item.Text, item, MapLayerClicked));
|
2021-12-05 17:16:14 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-12-08 17:50:03 +01:00
|
|
|
|
var initialLayer = MapLayers.Select(l => l.GetLayer()).FirstOrDefault();
|
2021-12-05 17:16:14 +01:00
|
|
|
|
|
2022-01-13 20:12:49 +01:00
|
|
|
|
if (MapOverlays.Count > 0)
|
2021-12-05 17:16:14 +01:00
|
|
|
|
{
|
|
|
|
|
|
if (initialLayer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
menu.Items.Add(CreateSeparator());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-01-13 20:12:49 +01:00
|
|
|
|
foreach (var item in MapOverlays)
|
2021-12-05 17:16:14 +01:00
|
|
|
|
{
|
2022-12-08 17:50:03 +01:00
|
|
|
|
menu.Items.Add(CreateMenuItem(item.Text, item, MapOverlayClicked));
|
2021-12-05 17:16:14 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (initialLayer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
SetMapLayer(initialLayer);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void MapLayerClicked(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
var item = (FrameworkElement)sender;
|
2022-12-08 17:50:03 +01:00
|
|
|
|
var mapLayerItem = (MapLayerItem)item.Tag;
|
2021-12-05 17:16:14 +01:00
|
|
|
|
|
2022-12-08 17:50:03 +01:00
|
|
|
|
SetMapLayer(mapLayerItem.GetLayer());
|
2021-12-05 17:16:14 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void MapOverlayClicked(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
var item = (FrameworkElement)sender;
|
2022-12-08 17:50:03 +01:00
|
|
|
|
var mapLayerItem = (MapLayerItem)item.Tag;
|
2021-12-05 17:16:14 +01:00
|
|
|
|
|
2022-12-08 17:50:03 +01:00
|
|
|
|
ToggleMapOverlay(mapLayerItem.GetLayer());
|
2021-12-05 17:16:14 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-24 15:15:29 +02:00
|
|
|
|
private void SetMapLayer(FrameworkElement layer)
|
2021-12-05 17:16:14 +01:00
|
|
|
|
{
|
2022-01-21 18:37:05 +01:00
|
|
|
|
if (selectedLayer != layer)
|
|
|
|
|
|
{
|
|
|
|
|
|
selectedLayer = layer;
|
|
|
|
|
|
Map.MapLayer = selectedLayer;
|
|
|
|
|
|
}
|
2021-12-05 17:16:14 +01:00
|
|
|
|
|
|
|
|
|
|
UpdateCheckedStates();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-24 15:15:29 +02:00
|
|
|
|
private void ToggleMapOverlay(FrameworkElement layer)
|
2021-12-05 17:16:14 +01:00
|
|
|
|
{
|
|
|
|
|
|
if (Map.Children.Contains(layer))
|
|
|
|
|
|
{
|
|
|
|
|
|
Map.Children.Remove(layer);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
int index = 1;
|
|
|
|
|
|
|
2022-12-08 17:50:03 +01:00
|
|
|
|
foreach (var overlay in MapOverlays.Select(o => o.Layer).Where(o => o != null))
|
2021-12-05 17:16:14 +01:00
|
|
|
|
{
|
|
|
|
|
|
if (overlay == layer)
|
|
|
|
|
|
{
|
|
|
|
|
|
Map.Children.Insert(index, layer);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (Map.Children.Contains(overlay))
|
|
|
|
|
|
{
|
|
|
|
|
|
index++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UpdateCheckedStates();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void UpdateCheckedStates()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var item in GetMenuItems())
|
|
|
|
|
|
{
|
2022-12-08 17:50:03 +01:00
|
|
|
|
item.IsChecked = Map.Children.Contains(((MapLayerItem)item.Tag).Layer);
|
2021-12-05 17:16:14 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|