mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2026-04-05 14:37:01 +00:00
New menu item implementation based directly on MenuItem/ToggleMenuFlyoutItem
This commit is contained in:
parent
11cd45c099
commit
e06dcc5155
12 changed files with 335 additions and 412 deletions
90
MapUiTools/Shared/MapLayerMenuItem.cs
Normal file
90
MapUiTools/Shared/MapLayerMenuItem.cs
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
#if WPF
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
#elif UWP
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Markup;
|
||||
#elif WINUI
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Markup;
|
||||
#else
|
||||
using Avalonia.Metadata;
|
||||
using FrameworkElement = Avalonia.Controls.Control;
|
||||
#endif
|
||||
|
||||
namespace MapControl.UiTools
|
||||
{
|
||||
#if WPF
|
||||
[ContentProperty(nameof(MapLayer))]
|
||||
#elif UWP || WINUI
|
||||
[ContentProperty(Name = nameof(MapLayer))]
|
||||
#endif
|
||||
public class MapLayerMenuItem : MapMenuItem
|
||||
{
|
||||
#if AVALONIA
|
||||
[Content]
|
||||
#endif
|
||||
public FrameworkElement MapLayer { get; set; }
|
||||
|
||||
public Func<Task<FrameworkElement>> MapLayerFactory { get; set; }
|
||||
|
||||
public MapLayerMenuItem()
|
||||
{
|
||||
Click += async (s, e) =>
|
||||
{
|
||||
if (DataContext is MapBase map)
|
||||
{
|
||||
await Execute(map);
|
||||
|
||||
foreach (var item in ParentMenuItems.OfType<MapLayerMenuItem>())
|
||||
{
|
||||
item.IsChecked = map.Children.Contains(item.MapLayer);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public virtual async Task Execute(MapBase map)
|
||||
{
|
||||
map.MapLayer = MapLayer ?? (MapLayer = await MapLayerFactory.Invoke());
|
||||
IsChecked = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class MapOverlayMenuItem : MapLayerMenuItem
|
||||
{
|
||||
public override async Task Execute(MapBase map)
|
||||
{
|
||||
var layer = MapLayer ?? (MapLayer = await MapLayerFactory.Invoke());
|
||||
|
||||
if (map.Children.Contains(layer))
|
||||
{
|
||||
map.Children.Remove(layer);
|
||||
}
|
||||
else
|
||||
{
|
||||
var index = 1;
|
||||
|
||||
foreach (var itemLayer in ParentMenuItems?
|
||||
.OfType<MapOverlayMenuItem>()
|
||||
.Select(item => item.MapLayer)
|
||||
.Where(itemLayer => itemLayer != null))
|
||||
{
|
||||
if (itemLayer == layer)
|
||||
{
|
||||
map.Children.Insert(index, itemLayer);
|
||||
break;
|
||||
}
|
||||
|
||||
if (map.Children.Contains(itemLayer))
|
||||
{
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
#if WPF
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
#elif UWP
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Markup;
|
||||
#elif WINUI
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Markup;
|
||||
#elif AVALONIA
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Metadata;
|
||||
using DependencyProperty = Avalonia.AvaloniaProperty;
|
||||
using FrameworkElement = Avalonia.Controls.Control;
|
||||
#endif
|
||||
|
||||
namespace MapControl.UiTools
|
||||
{
|
||||
#if WPF
|
||||
[ContentProperty(nameof(Layer))]
|
||||
#elif UWP || WINUI
|
||||
[ContentProperty(Name = nameof(Layer))]
|
||||
#endif
|
||||
public class MapLayerItem
|
||||
{
|
||||
#if AVALONIA
|
||||
[Content]
|
||||
#endif
|
||||
public FrameworkElement Layer { get; set; }
|
||||
|
||||
public string Text { get; set; }
|
||||
|
||||
public Func<Task<FrameworkElement>> LayerFactory { get; set; }
|
||||
|
||||
public async Task<FrameworkElement> GetLayer() => Layer ?? (Layer = await LayerFactory?.Invoke());
|
||||
}
|
||||
|
||||
#if WPF
|
||||
[ContentProperty(nameof(MapLayers))]
|
||||
#elif UWP || WINUI
|
||||
[ContentProperty(Name = nameof(MapLayers))]
|
||||
#endif
|
||||
public class MapLayersMenuButton : MenuButton
|
||||
{
|
||||
private FrameworkElement selectedLayer;
|
||||
|
||||
public MapLayersMenuButton()
|
||||
: base("\uE81E")
|
||||
{
|
||||
((INotifyCollectionChanged)MapLayers).CollectionChanged += async (s, e) => await InitializeMenu();
|
||||
((INotifyCollectionChanged)MapOverlays).CollectionChanged += async (s, e) => await InitializeMenu();
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MapProperty =
|
||||
DependencyPropertyHelper.Register<MapLayersMenuButton, MapBase>(nameof(Map), null,
|
||||
async (button, oldValue, newValue) => await button.InitializeMenu());
|
||||
|
||||
public MapBase Map
|
||||
{
|
||||
get => (MapBase)GetValue(MapProperty);
|
||||
set => SetValue(MapProperty, value);
|
||||
}
|
||||
|
||||
#if AVALONIA
|
||||
[Content]
|
||||
#endif
|
||||
public Collection<MapLayerItem> MapLayers { get; } = new ObservableCollection<MapLayerItem>();
|
||||
|
||||
public Collection<MapLayerItem> MapOverlays { get; } = new ObservableCollection<MapLayerItem>();
|
||||
|
||||
private async Task InitializeMenu()
|
||||
{
|
||||
if (Map != null)
|
||||
{
|
||||
var menu = CreateMenu();
|
||||
|
||||
foreach (var item in MapLayers)
|
||||
{
|
||||
menu.Items.Add(CreateMenuItem(item.Text, item, MapLayerClicked));
|
||||
}
|
||||
|
||||
var initialLayer = MapLayers.Select(l => l.GetLayer()).FirstOrDefault();
|
||||
|
||||
if (MapOverlays.Count > 0)
|
||||
{
|
||||
if (initialLayer != null)
|
||||
{
|
||||
menu.Items.Add(CreateSeparator());
|
||||
}
|
||||
|
||||
foreach (var item in MapOverlays)
|
||||
{
|
||||
menu.Items.Add(CreateMenuItem(item.Text, item, MapOverlayClicked));
|
||||
}
|
||||
}
|
||||
|
||||
if (initialLayer != null)
|
||||
{
|
||||
SetMapLayer(await initialLayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void MapLayerClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var item = (FrameworkElement)sender;
|
||||
var mapLayerItem = (MapLayerItem)item.Tag;
|
||||
|
||||
SetMapLayer(await mapLayerItem.GetLayer());
|
||||
}
|
||||
|
||||
private async void MapOverlayClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var item = (FrameworkElement)sender;
|
||||
var mapLayerItem = (MapLayerItem)item.Tag;
|
||||
|
||||
ToggleMapOverlay(await mapLayerItem.GetLayer());
|
||||
}
|
||||
|
||||
private void SetMapLayer(FrameworkElement layer)
|
||||
{
|
||||
if (selectedLayer != layer)
|
||||
{
|
||||
selectedLayer = layer;
|
||||
Map.MapLayer = selectedLayer;
|
||||
}
|
||||
|
||||
UpdateCheckedStates();
|
||||
}
|
||||
|
||||
private void ToggleMapOverlay(FrameworkElement layer)
|
||||
{
|
||||
if (Map.Children.Contains(layer))
|
||||
{
|
||||
Map.Children.Remove(layer);
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = 1;
|
||||
|
||||
foreach (var overlay in MapOverlays.Select(o => o.Layer).Where(o => o != null))
|
||||
{
|
||||
if (overlay == layer)
|
||||
{
|
||||
Map.Children.Insert(index, layer);
|
||||
break;
|
||||
}
|
||||
|
||||
if (Map.Children.Contains(overlay))
|
||||
{
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateCheckedStates();
|
||||
}
|
||||
|
||||
private void UpdateCheckedStates()
|
||||
{
|
||||
foreach (var item in GetMenuItems())
|
||||
{
|
||||
item.IsChecked = Map.Children.Contains(((MapLayerItem)item.Tag).Layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
64
MapUiTools/Shared/MapProjectionMenuItem.cs
Normal file
64
MapUiTools/Shared/MapProjectionMenuItem.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
#if WPF
|
||||
using System.Windows.Markup;
|
||||
#elif UWP
|
||||
using Windows.UI.Xaml.Markup;
|
||||
#elif WINUI
|
||||
using Microsoft.UI.Xaml.Markup;
|
||||
#else
|
||||
using Avalonia.Metadata;
|
||||
#endif
|
||||
|
||||
namespace MapControl.UiTools
|
||||
{
|
||||
#if WPF
|
||||
[ContentProperty(nameof(MapProjection))]
|
||||
#elif UWP || WINUI
|
||||
[ContentProperty(Name = nameof(MapProjection))]
|
||||
#endif
|
||||
public class MapProjectionMenuItem : MapMenuItem
|
||||
{
|
||||
#if AVALONIA
|
||||
[Content]
|
||||
#endif
|
||||
public string MapProjection { get; set; }
|
||||
|
||||
public MapProjectionMenuItem()
|
||||
{
|
||||
Click += (s, e) =>
|
||||
{
|
||||
if (DataContext is MapBase map)
|
||||
{
|
||||
Execute(map);
|
||||
|
||||
foreach (var item in ParentMenuItems.OfType<MapProjectionMenuItem>())
|
||||
{
|
||||
item.IsChecked = map.MapProjection.CrsId == item.MapProjection;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void Execute(MapBase map)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
if (map.MapProjection.CrsId != MapProjection)
|
||||
{
|
||||
try
|
||||
{
|
||||
map.MapProjection = MapProjectionFactory.Instance.GetProjection(MapProjection);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"{nameof(MapProjectionFactory)}: {ex.Message}");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
IsChecked = success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
#if WPF
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
#elif UWP
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Markup;
|
||||
#elif WINUI
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Markup;
|
||||
#elif AVALONIA
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Metadata;
|
||||
using DependencyProperty = Avalonia.AvaloniaProperty;
|
||||
using FrameworkElement = Avalonia.Controls.Control;
|
||||
#endif
|
||||
|
||||
namespace MapControl.UiTools
|
||||
{
|
||||
#if WPF
|
||||
[ContentProperty(nameof(Projection))]
|
||||
#elif UWP || WINUI
|
||||
[ContentProperty(Name = nameof(Projection))]
|
||||
#endif
|
||||
public class MapProjectionItem
|
||||
{
|
||||
#if AVALONIA
|
||||
[Content]
|
||||
#endif
|
||||
public string Projection { get; set; }
|
||||
|
||||
public string Text { get; set; }
|
||||
}
|
||||
|
||||
#if WPF
|
||||
[ContentProperty(nameof(MapProjections))]
|
||||
#elif UWP || WINUI
|
||||
[ContentProperty(Name = nameof(MapProjections))]
|
||||
#endif
|
||||
public class MapProjectionsMenuButton : MenuButton
|
||||
{
|
||||
private string selectedProjection;
|
||||
|
||||
public MapProjectionsMenuButton()
|
||||
: base("\uE809")
|
||||
{
|
||||
((INotifyCollectionChanged)MapProjections).CollectionChanged += (s, e) => InitializeMenu();
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MapProperty =
|
||||
DependencyPropertyHelper.Register<MapProjectionsMenuButton, MapBase>(nameof(Map), null,
|
||||
(button, oldValue, newValue) => button.InitializeMenu());
|
||||
|
||||
public MapBase Map
|
||||
{
|
||||
get => (MapBase)GetValue(MapProperty);
|
||||
set => SetValue(MapProperty, value);
|
||||
}
|
||||
|
||||
#if AVALONIA
|
||||
[Content]
|
||||
#endif
|
||||
public Collection<MapProjectionItem> MapProjections { get; } = new ObservableCollection<MapProjectionItem>();
|
||||
|
||||
private void InitializeMenu()
|
||||
{
|
||||
if (Map != null)
|
||||
{
|
||||
var menu = CreateMenu();
|
||||
|
||||
foreach (var item in MapProjections)
|
||||
{
|
||||
menu.Items.Add(CreateMenuItem(item.Text, item.Projection, MapProjectionClicked));
|
||||
}
|
||||
|
||||
var initialProjection = MapProjections.Select(p => p.Projection).FirstOrDefault();
|
||||
|
||||
if (initialProjection != null)
|
||||
{
|
||||
SetMapProjection(initialProjection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MapProjectionClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var item = (FrameworkElement)sender;
|
||||
var projection = (string)item.Tag;
|
||||
|
||||
SetMapProjection(projection);
|
||||
}
|
||||
|
||||
private void SetMapProjection(string projection)
|
||||
{
|
||||
if (selectedProjection != projection)
|
||||
{
|
||||
try
|
||||
{
|
||||
Map.MapProjection = MapProjectionFactory.Instance.GetProjection(projection);
|
||||
selectedProjection = projection;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"{nameof(MapProjectionFactory)}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
UpdateCheckedStates();
|
||||
}
|
||||
|
||||
private void UpdateCheckedStates()
|
||||
{
|
||||
foreach (var item in GetMenuItems())
|
||||
{
|
||||
item.IsChecked = selectedProjection == (string)item.Tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
50
MapUiTools/Shared/MenuButton.cs
Normal file
50
MapUiTools/Shared/MenuButton.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
using System.Threading.Tasks;
|
||||
#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;
|
||||
#else
|
||||
using Avalonia.Controls;
|
||||
using DependencyProperty = Avalonia.AvaloniaProperty;
|
||||
#endif
|
||||
|
||||
namespace MapControl.UiTools
|
||||
{
|
||||
public partial class MenuButton : Button
|
||||
{
|
||||
public static readonly DependencyProperty MapProperty =
|
||||
DependencyPropertyHelper.Register<MenuButton, MapBase>(nameof(Map), null,
|
||||
async (button, oldValue, newValue) => await button.Initialize());
|
||||
|
||||
public MapBase Map
|
||||
{
|
||||
get => (MapBase)GetValue(MapProperty);
|
||||
set => SetValue(MapProperty, value);
|
||||
}
|
||||
|
||||
private async Task Initialize()
|
||||
{
|
||||
if (Map != null)
|
||||
{
|
||||
DataContext = Map;
|
||||
|
||||
if (Items.Count > 0)
|
||||
{
|
||||
if (Items[0] is MapLayerMenuItem mapLayerItem)
|
||||
{
|
||||
await mapLayerItem.Execute(Map);
|
||||
}
|
||||
else if (Items[0] is MapProjectionMenuItem mapProjectionItem)
|
||||
{
|
||||
mapProjectionItem.Execute(Map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue