mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
New menu item implementation based directly on MenuItem/ToggleMenuFlyoutItem
This commit is contained in:
parent
11cd45c099
commit
e06dcc5155
42
MapUiTools/Avalonia/MapMenuItem.Avalonia.cs
Normal file
42
MapUiTools/Avalonia/MapMenuItem.Avalonia.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MapControl.UiTools
|
||||||
|
{
|
||||||
|
public class MapMenuItem : MenuItem
|
||||||
|
{
|
||||||
|
public MapMenuItem()
|
||||||
|
{
|
||||||
|
Icon = new TextBlock
|
||||||
|
{
|
||||||
|
FontFamily = new("Segoe MDL2 Assets"),
|
||||||
|
FontWeight = FontWeight.Black,
|
||||||
|
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get => Header as string;
|
||||||
|
set => Header = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IEnumerable<MapMenuItem> ParentMenuItems => (Parent as ItemsControl)?.Items.OfType<MapMenuItem>();
|
||||||
|
|
||||||
|
protected override Type StyleKeyOverride => typeof(MenuItem);
|
||||||
|
|
||||||
|
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs args)
|
||||||
|
{
|
||||||
|
base.OnPropertyChanged(args);
|
||||||
|
|
||||||
|
if (args.Property == IsCheckedProperty)
|
||||||
|
{
|
||||||
|
((TextBlock)Icon).Text = (bool)args.NewValue ? "\uE73E" : ""; // CheckMark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,81 +1,37 @@
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
|
using Avalonia.Metadata;
|
||||||
using Avalonia.Styling;
|
using Avalonia.Styling;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl.UiTools
|
||||||
{
|
{
|
||||||
public class ToggleMenuFlyoutItem : MenuItem
|
public partial class MenuButton
|
||||||
{
|
{
|
||||||
internal static readonly FontFamily SymbolFont = new("Segoe MDL2 Assets");
|
public MenuButton()
|
||||||
|
|
||||||
private readonly TextBlock icon = new()
|
|
||||||
{
|
|
||||||
FontFamily = SymbolFont,
|
|
||||||
FontWeight = FontWeight.Black,
|
|
||||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
|
||||||
};
|
|
||||||
|
|
||||||
public ToggleMenuFlyoutItem(string text, object item, EventHandler<RoutedEventArgs> click)
|
|
||||||
{
|
|
||||||
Icon = icon;
|
|
||||||
Header = text;
|
|
||||||
Tag = item;
|
|
||||||
Click += click;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Type StyleKeyOverride => typeof(MenuItem);
|
|
||||||
|
|
||||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs args)
|
|
||||||
{
|
|
||||||
base.OnPropertyChanged(args);
|
|
||||||
|
|
||||||
if (args.Property == IsCheckedProperty)
|
|
||||||
{
|
|
||||||
icon.Text = (bool)args.NewValue ? "\uE73E" : ""; // CheckMark
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MenuButton : Button
|
|
||||||
{
|
|
||||||
protected MenuButton(string icon)
|
|
||||||
{
|
{
|
||||||
var style = new Style();
|
var style = new Style();
|
||||||
style.Setters.Add(new Setter(TextBlock.FontFamilyProperty, ToggleMenuFlyoutItem.SymbolFont));
|
style.Setters.Add(new Setter(TextBlock.FontFamilyProperty, new FontFamily("Segoe MDL2 Assets")));
|
||||||
style.Setters.Add(new Setter(TextBlock.FontSizeProperty, 20d));
|
style.Setters.Add(new Setter(TextBlock.FontSizeProperty, 20d));
|
||||||
style.Setters.Add(new Setter(PaddingProperty, new Thickness(8)));
|
style.Setters.Add(new Setter(PaddingProperty, new Thickness(8)));
|
||||||
Styles.Add(style);
|
Styles.Add(style);
|
||||||
|
|
||||||
Content = icon;
|
Flyout = new MenuFlyout();
|
||||||
|
Loaded += async (s, e) => await Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Icon
|
||||||
|
{
|
||||||
|
get => Content as string;
|
||||||
|
set => Content = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MenuFlyout Menu => (MenuFlyout)Flyout;
|
||||||
|
|
||||||
|
[Content]
|
||||||
|
public ItemCollection Items => Menu.Items;
|
||||||
|
|
||||||
protected override Type StyleKeyOverride => typeof(Button);
|
protected override Type StyleKeyOverride => typeof(Button);
|
||||||
|
|
||||||
protected MenuFlyout CreateMenu()
|
|
||||||
{
|
|
||||||
var menu = new MenuFlyout();
|
|
||||||
Flyout = menu;
|
|
||||||
return menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected IEnumerable<ToggleMenuFlyoutItem> GetMenuItems()
|
|
||||||
{
|
|
||||||
return ((MenuFlyout)Flyout).Items.OfType<ToggleMenuFlyoutItem>();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static MenuItem CreateMenuItem(string text, object item, EventHandler<RoutedEventArgs> click)
|
|
||||||
{
|
|
||||||
return new ToggleMenuFlyoutItem(text, item, click);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static Separator CreateSeparator()
|
|
||||||
{
|
|
||||||
return new Separator();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -40,11 +40,17 @@
|
||||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\Shared\MapLayersMenuButton.cs">
|
<Compile Include="..\Shared\MapLayerMenuItem.cs">
|
||||||
<Link>MapLayersMenuButton.cs</Link>
|
<Link>MapLayerMenuItem.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\Shared\MapProjectionsMenuButton.cs">
|
<Compile Include="..\Shared\MapProjectionMenuItem.cs">
|
||||||
<Link>MapProjectionsMenuButton.cs</Link>
|
<Link>MapProjectionMenuItem.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Shared\MenuButton.cs">
|
||||||
|
<Link>MenuButton.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\WinUI\MapMenuItem.WinUI.cs">
|
||||||
|
<Link>MapMenuItem.WinUI.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\WinUI\MenuButton.WinUI.cs">
|
<Compile Include="..\WinUI\MenuButton.WinUI.cs">
|
||||||
<Link>MenuButton.WinUI.cs</Link>
|
<Link>MenuButton.WinUI.cs</Link>
|
||||||
|
|
|
||||||
18
MapUiTools/WPF/MapMenuItem.WPF.cs
Normal file
18
MapUiTools/WPF/MapMenuItem.WPF.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace MapControl.UiTools
|
||||||
|
{
|
||||||
|
public class MapMenuItem : MenuItem
|
||||||
|
{
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get => Header as string;
|
||||||
|
set => Header = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IEnumerable<MapMenuItem> ParentMenuItems
|
||||||
|
=> (Parent as ItemsControl)?.Items.OfType<MapMenuItem>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,46 +1,33 @@
|
||||||
using System.Collections.Generic;
|
using System.Windows;
|
||||||
using System.Linq;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Markup;
|
||||||
|
|
||||||
namespace MapControl.UiTools
|
namespace MapControl.UiTools
|
||||||
{
|
{
|
||||||
public class MenuButton : Button
|
[ContentProperty(nameof(Items))]
|
||||||
|
public partial class MenuButton
|
||||||
{
|
{
|
||||||
static MenuButton()
|
static MenuButton()
|
||||||
{
|
{
|
||||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(MenuButton), new FrameworkPropertyMetadata(typeof(MenuButton)));
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(MenuButton), new FrameworkPropertyMetadata(typeof(MenuButton)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MenuButton(string icon)
|
public MenuButton()
|
||||||
{
|
{
|
||||||
Content = icon;
|
ContextMenu = new ContextMenu();
|
||||||
|
DataContextChanged += (s, e) => ContextMenu.DataContext = e.NewValue;
|
||||||
|
Loaded += async (s, e) => await Initialize();
|
||||||
Click += (s, e) => ContextMenu.IsOpen = true;
|
Click += (s, e) => ContextMenu.IsOpen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ContextMenu CreateMenu()
|
public string Icon
|
||||||
{
|
{
|
||||||
var menu = new ContextMenu();
|
get => Content as string;
|
||||||
ContextMenu = menu;
|
set => Content = value;
|
||||||
return menu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IEnumerable<MenuItem> GetMenuItems()
|
public ContextMenu Menu => ContextMenu;
|
||||||
{
|
|
||||||
return ContextMenu.Items.OfType<MenuItem>();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static MenuItem CreateMenuItem(string text, object item, RoutedEventHandler click)
|
public ItemCollection Items => ContextMenu.Items;
|
||||||
{
|
|
||||||
var menuItem = new MenuItem { Header = text, Tag = item };
|
|
||||||
menuItem.Click += click;
|
|
||||||
return menuItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static Separator CreateSeparator()
|
|
||||||
{
|
|
||||||
return new Separator();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
MapUiTools/WinUI/MapMenuItem.WinUI.cs
Normal file
18
MapUiTools/WinUI/MapMenuItem.WinUI.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
#if UWP
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
using Windows.UI.Xaml.Media;
|
||||||
|
#else
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Microsoft.UI.Xaml.Media;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace MapControl.UiTools
|
||||||
|
{
|
||||||
|
public class MapMenuItem : ToggleMenuFlyoutItem
|
||||||
|
{
|
||||||
|
protected IEnumerable<MapMenuItem> ParentMenuItems
|
||||||
|
=> (VisualTreeHelper.GetParent(this) as Panel)?.Children.OfType<MapMenuItem>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,44 +1,31 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
#if UWP
|
#if UWP
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
|
using Windows.UI.Xaml.Markup;
|
||||||
#elif WINUI
|
#elif WINUI
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Microsoft.UI.Xaml.Markup;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace MapControl.UiTools
|
namespace MapControl.UiTools
|
||||||
{
|
{
|
||||||
public class MenuButton : Button
|
[ContentProperty(Name = nameof(Items))]
|
||||||
|
public partial class MenuButton
|
||||||
{
|
{
|
||||||
protected MenuButton(string icon)
|
public MenuButton()
|
||||||
{
|
{
|
||||||
Content = new FontIcon { Glyph = icon };
|
Flyout = new MenuFlyout();
|
||||||
|
Loaded += async (s, e) => await Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MenuFlyout CreateMenu()
|
public string Icon
|
||||||
{
|
{
|
||||||
var menu = new MenuFlyout();
|
get => (Content as FontIcon)?.Glyph;
|
||||||
Flyout = menu;
|
set => Content = new FontIcon { Glyph = value };
|
||||||
return menu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IEnumerable<ToggleMenuFlyoutItem> GetMenuItems()
|
public MenuFlyout Menu => (MenuFlyout)Flyout;
|
||||||
{
|
|
||||||
return ((MenuFlyout)Flyout).Items.OfType<ToggleMenuFlyoutItem>();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static ToggleMenuFlyoutItem CreateMenuItem(string text, object item, RoutedEventHandler click)
|
public IList<MenuFlyoutItemBase> Items => Menu.Items;
|
||||||
{
|
|
||||||
var menuItem = new ToggleMenuFlyoutItem { Text = text, Tag = item };
|
|
||||||
menuItem.Click += click;
|
|
||||||
return menuItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static MenuFlyoutSeparator CreateSeparator()
|
|
||||||
{
|
|
||||||
return new MenuFlyoutSeparator();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue