File scoped namespaces

This commit is contained in:
ClemensFischer 2026-04-13 17:14:49 +02:00
parent c14377f976
commit 65aba44af6
152 changed files with 11962 additions and 12115 deletions

View file

@ -5,41 +5,40 @@ using System;
using System.Collections.Generic;
using System.Linq;
namespace MapControl.UiTools
namespace MapControl.UiTools;
public abstract partial class MapMenuItem : MenuItem
{
public abstract partial class MapMenuItem : MenuItem
protected MapMenuItem()
{
protected MapMenuItem()
Icon = new TextBlock
{
Icon = new TextBlock
{
FontFamily = new FontFamily("Segoe MDL2 Assets"),
FontWeight = FontWeight.Black,
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
};
FontFamily = new FontFamily("Segoe MDL2 Assets"),
FontWeight = FontWeight.Black,
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
};
Loaded += (_, _) => Initialize();
Click += (_, _) => Execute();
}
Loaded += (_, _) => Initialize();
Click += (_, _) => Execute();
}
public string Text
public string Text
{
get => Header as string;
set => Header = value;
}
protected IEnumerable<MapMenuItem> ParentMenuItems => ((ItemsControl)Parent).Items.OfType<MapMenuItem>();
protected override Type StyleKeyOverride => typeof(MenuItem);
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs args)
{
base.OnPropertyChanged(args);
if (args.Property == IsCheckedProperty)
{
get => Header as string;
set => Header = value;
}
protected IEnumerable<MapMenuItem> ParentMenuItems => ((ItemsControl)Parent).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
}
((TextBlock)Icon).Text = (bool)args.NewValue ? "\uE73E" : ""; // CheckMark
}
}
}

View file

@ -5,33 +5,32 @@ using Avalonia.Metadata;
using Avalonia.Styling;
using System;
namespace MapControl.UiTools
namespace MapControl.UiTools;
public partial class MenuButton
{
public partial class MenuButton
public MenuButton()
{
public MenuButton()
{
var style = new Style();
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(PaddingProperty, new Thickness(8)));
Styles.Add(style);
var style = new Style();
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(PaddingProperty, new Thickness(8)));
Styles.Add(style);
Flyout = new MenuFlyout();
Loaded += async (_, _) => 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);
Flyout = new MenuFlyout();
Loaded += async (_, _) => 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);
}

View file

@ -22,109 +22,108 @@ using Avalonia.Media;
using DependencyProperty = Avalonia.AvaloniaProperty;
#endif
namespace MapControl.UiTools
namespace MapControl.UiTools;
public static class HyperlinkText
{
public static class HyperlinkText
private static readonly Regex regex = new Regex(@"\[([^\]]+)\]\(([^\)]+)\)");
/// <summary>
/// Converts text containing hyperlinks in markdown syntax [text](url)
/// to a collection of Run and Hyperlink inlines.
/// </summary>
public static IEnumerable<Inline> TextToInlines(this string text)
{
private static readonly Regex regex = new Regex(@"\[([^\]]+)\]\(([^\)]+)\)");
var inlines = new List<Inline>();
/// <summary>
/// Converts text containing hyperlinks in markdown syntax [text](url)
/// to a collection of Run and Hyperlink inlines.
/// </summary>
public static IEnumerable<Inline> TextToInlines(this string text)
while (!string.IsNullOrEmpty(text))
{
var inlines = new List<Inline>();
var match = regex.Match(text);
while (!string.IsNullOrEmpty(text))
if (match.Success &&
match.Groups.Count == 3 &&
Uri.TryCreate(match.Groups[2].Value, UriKind.Absolute, out Uri uri))
{
var match = regex.Match(text);
if (match.Success &&
match.Groups.Count == 3 &&
Uri.TryCreate(match.Groups[2].Value, UriKind.Absolute, out Uri uri))
inlines.Add(new Run
{
inlines.Add(new Run
{
Text = text.Substring(0, match.Index),
Text = text.Substring(0, match.Index),
#if WPF || AVALONIA
BaselineAlignment = BaselineAlignment.Center
BaselineAlignment = BaselineAlignment.Center
#endif
});
text = text.Substring(match.Index + match.Length);
var hyperlinkText = match.Groups[1].Value;
#if AVALONIA
var button = new HyperlinkButton
{
Content = hyperlinkText,
NavigateUri = uri,
Padding = new Thickness(0),
Margin = new Thickness(0)
};
var link = new InlineUIContainer
{
Child = button,
BaselineAlignment = BaselineAlignment.Center
};
#else
var run = new Run { Text = hyperlinkText };
var link = new Hyperlink { NavigateUri = uri };
link.Inlines.Add(run);
#if WPF
run.BaselineAlignment = BaselineAlignment.Center;
link.BaselineAlignment = BaselineAlignment.Center;
link.ToolTip = uri.ToString();
link.RequestNavigate += (_, e) =>
{
try
{
Process.Start(new ProcessStartInfo(e.Uri.ToString()) { UseShellExecute = true });
}
catch (Exception ex)
{
Debug.WriteLine($"{e.Uri}: {ex}");
}
};
#endif
#endif
inlines.Add(link);
}
else
{
inlines.Add(new Run { Text = text });
text = null;
}
}
return inlines;
}
public static readonly DependencyProperty InlinesSourceProperty =
DependencyPropertyHelper.RegisterAttached<string>("InlinesSource", typeof(HyperlinkText), null,
(element, oldValue, newValue) =>
{
if (element is TextBlock textBlock)
{
textBlock.Inlines.Clear();
foreach (var inline in TextToInlines(newValue))
{
textBlock.Inlines.Add(inline);
}
}
});
public static string GetInlinesSource(TextBlock element)
{
return (string)element.GetValue(InlinesSourceProperty);
text = text.Substring(match.Index + match.Length);
var hyperlinkText = match.Groups[1].Value;
#if AVALONIA
var button = new HyperlinkButton
{
Content = hyperlinkText,
NavigateUri = uri,
Padding = new Thickness(0),
Margin = new Thickness(0)
};
var link = new InlineUIContainer
{
Child = button,
BaselineAlignment = BaselineAlignment.Center
};
#else
var run = new Run { Text = hyperlinkText };
var link = new Hyperlink { NavigateUri = uri };
link.Inlines.Add(run);
#if WPF
run.BaselineAlignment = BaselineAlignment.Center;
link.BaselineAlignment = BaselineAlignment.Center;
link.ToolTip = uri.ToString();
link.RequestNavigate += (_, e) =>
{
try
{
Process.Start(new ProcessStartInfo(e.Uri.ToString()) { UseShellExecute = true });
}
catch (Exception ex)
{
Debug.WriteLine($"{e.Uri}: {ex}");
}
};
#endif
#endif
inlines.Add(link);
}
else
{
inlines.Add(new Run { Text = text });
text = null;
}
}
public static void SetInlinesSource(TextBlock element, string value)
{
element.SetValue(InlinesSourceProperty, value);
}
return inlines;
}
public static readonly DependencyProperty InlinesSourceProperty =
DependencyPropertyHelper.RegisterAttached<string>("InlinesSource", typeof(HyperlinkText), null,
(element, oldValue, newValue) =>
{
if (element is TextBlock textBlock)
{
textBlock.Inlines.Clear();
foreach (var inline in TextToInlines(newValue))
{
textBlock.Inlines.Add(inline);
}
}
});
public static string GetInlinesSource(TextBlock element)
{
return (string)element.GetValue(InlinesSourceProperty);
}
public static void SetInlinesSource(TextBlock element, string value)
{
element.SetValue(InlinesSourceProperty, value);
}
}

View file

@ -13,22 +13,21 @@ using DependencyProperty = Avalonia.AvaloniaProperty;
using FrameworkElement = Avalonia.Controls.Control;
#endif
namespace MapControl.UiTools
namespace MapControl.UiTools;
public partial class MapLayerInfo : UserControl
{
public partial class MapLayerInfo : UserControl
public static readonly DependencyProperty MapLayerProperty =
DependencyPropertyHelper.Register<MapLayerInfo, FrameworkElement>(nameof(MapLayer), null);
public FrameworkElement MapLayer
{
public static readonly DependencyProperty MapLayerProperty =
DependencyPropertyHelper.Register<MapLayerInfo, FrameworkElement>(nameof(MapLayer), null);
get => (FrameworkElement)GetValue(MapLayerProperty);
set => SetValue(MapLayerProperty, value);
}
public FrameworkElement MapLayer
{
get => (FrameworkElement)GetValue(MapLayerProperty);
set => SetValue(MapLayerProperty, value);
}
public MapLayerInfo()
{
InitializeComponent();
}
public MapLayerInfo()
{
InitializeComponent();
}
}

View file

@ -15,88 +15,87 @@ using Avalonia.Metadata;
using FrameworkElement = Avalonia.Controls.Control;
#endif
namespace MapControl.UiTools
{
namespace MapControl.UiTools;
#if WPF
[ContentProperty(nameof(MapLayer))]
[ContentProperty(nameof(MapLayer))]
#elif UWP || WINUI
[ContentProperty(Name = nameof(MapLayer))]
[ContentProperty(Name = nameof(MapLayer))]
#endif
public partial class MapLayerMenuItem : MapMenuItem
{
public partial class MapLayerMenuItem : MapMenuItem
{
#if AVALONIA
[Content]
[Content]
#endif
public FrameworkElement MapLayer { get; set; }
public FrameworkElement MapLayer { get; set; }
protected override bool GetIsChecked(MapBase map)
{
return MapLayer != null && map.Children.Contains(MapLayer);
}
public override Task ExecuteAsync(MapBase map)
{
if (MapLayer != null)
{
map.MapLayer = MapLayer;
}
return Task.CompletedTask;
}
protected override bool GetIsChecked(MapBase map)
{
return MapLayer != null && map.Children.Contains(MapLayer);
}
public partial class MapOverlayMenuItem : MapLayerMenuItem
public override Task ExecuteAsync(MapBase map)
{
public string SourcePath { get; set; }
public int InsertOrder { get; set; }
public double OverlayOpacity { get; set; } = 1d;
public override async Task ExecuteAsync(MapBase map)
if (MapLayer != null)
{
if (MapLayer == null)
{
await CreateMapLayer();
}
if (MapLayer != null)
{
if (map.Children.Contains(MapLayer))
{
map.Children.Remove(MapLayer);
}
else
{
var insertIndex = ParentMenuItems
.OfType<MapOverlayMenuItem>()
.Where(item => item.InsertOrder <= InsertOrder && item.GetIsChecked(map))
.Count();
if (map.MapLayer != null)
{
insertIndex++;
}
map.Children.Insert(insertIndex, MapLayer);
}
}
map.MapLayer = MapLayer;
}
protected virtual async Task CreateMapLayer()
{
var ext = Path.GetExtension(SourcePath).ToLower();
return Task.CompletedTask;
}
}
if (ext == ".kmz" || ext == ".kml")
public partial class MapOverlayMenuItem : MapLayerMenuItem
{
public string SourcePath { get; set; }
public int InsertOrder { get; set; }
public double OverlayOpacity { get; set; } = 1d;
public override async Task ExecuteAsync(MapBase map)
{
if (MapLayer == null)
{
await CreateMapLayer();
}
if (MapLayer != null)
{
if (map.Children.Contains(MapLayer))
{
MapLayer = await GroundOverlay.CreateAsync(SourcePath);
map.Children.Remove(MapLayer);
}
else
{
MapLayer = await GeoImage.CreateAsync(SourcePath);
}
var insertIndex = ParentMenuItems
.OfType<MapOverlayMenuItem>()
.Where(item => item.InsertOrder <= InsertOrder && item.GetIsChecked(map))
.Count();
MapLayer.Opacity = OverlayOpacity;
if (map.MapLayer != null)
{
insertIndex++;
}
map.Children.Insert(insertIndex, MapLayer);
}
}
}
protected virtual async Task CreateMapLayer()
{
var ext = Path.GetExtension(SourcePath).ToLower();
if (ext == ".kmz" || ext == ".kml")
{
MapLayer = await GroundOverlay.CreateAsync(SourcePath);
}
else
{
MapLayer = await GeoImage.CreateAsync(SourcePath);
}
MapLayer.Opacity = OverlayOpacity;
}
}

View file

@ -1,30 +1,29 @@
using System.Threading.Tasks;
namespace MapControl.UiTools
namespace MapControl.UiTools;
public abstract partial class MapMenuItem
{
public abstract partial class MapMenuItem
public abstract Task ExecuteAsync(MapBase map);
protected abstract bool GetIsChecked(MapBase map);
protected virtual bool GetIsEnabled(MapBase map) => true;
private void Initialize()
{
public abstract Task ExecuteAsync(MapBase map);
protected abstract bool GetIsChecked(MapBase map);
protected virtual bool GetIsEnabled(MapBase map) => true;
private void Initialize()
if (DataContext is MapBase map)
{
if (DataContext is MapBase map)
{
IsEnabled = GetIsEnabled(map);
IsChecked = GetIsChecked(map);
}
IsEnabled = GetIsEnabled(map);
IsChecked = GetIsChecked(map);
}
}
private async void Execute()
private async void Execute()
{
if (DataContext is MapBase map)
{
if (DataContext is MapBase map)
{
await ExecuteAsync(map);
}
await ExecuteAsync(map);
}
}
}

View file

@ -12,53 +12,52 @@ using Microsoft.UI.Xaml.Markup;
using Avalonia.Metadata;
#endif
namespace MapControl.UiTools
{
namespace MapControl.UiTools;
#if WPF
[ContentProperty(nameof(CrsId))]
[ContentProperty(nameof(CrsId))]
#elif UWP || WINUI
[ContentProperty(Name = nameof(CrsId))]
[ContentProperty(Name = nameof(CrsId))]
#endif
public partial class MapProjectionMenuItem : MapMenuItem
{
public partial class MapProjectionMenuItem : MapMenuItem
{
#if AVALONIA
[Content]
[Content]
#endif
public string CrsId { get; set; }
public string CrsId { get; set; }
protected override bool GetIsEnabled(MapBase map)
protected override bool GetIsEnabled(MapBase map)
{
var supportedCrsIds = map.MapLayer switch
{
var supportedCrsIds = map.MapLayer switch
WmsImageLayer wmsImageLayer => wmsImageLayer.SupportedCrsIds,
WmtsTileLayer wmtsTileLayer => wmtsTileLayer.TileMatrixSets.Keys,
MapTileLayer => [WebMercatorProjection.DefaultCrsId],
_ => null
};
return supportedCrsIds == null || supportedCrsIds.Contains(CrsId);
}
protected override bool GetIsChecked(MapBase map)
{
return map.MapProjection.CrsId == CrsId;
}
public override Task ExecuteAsync(MapBase map)
{
if (!GetIsChecked(map))
{
try
{
WmsImageLayer wmsImageLayer => wmsImageLayer.SupportedCrsIds,
WmtsTileLayer wmtsTileLayer => wmtsTileLayer.TileMatrixSets.Keys,
MapTileLayer => [WebMercatorProjection.DefaultCrsId],
_ => null
};
return supportedCrsIds == null || supportedCrsIds.Contains(CrsId);
}
protected override bool GetIsChecked(MapBase map)
{
return map.MapProjection.CrsId == CrsId;
}
public override Task ExecuteAsync(MapBase map)
{
if (!GetIsChecked(map))
{
try
{
map.MapProjection = MapProjection.Parse(CrsId);
}
catch (Exception ex)
{
Debug.WriteLine($"MapProjection.Parse: {ex.Message}");
}
map.MapProjection = MapProjection.Parse(CrsId);
}
catch (Exception ex)
{
Debug.WriteLine($"MapProjection.Parse: {ex.Message}");
}
return Task.CompletedTask;
}
return Task.CompletedTask;
}
}

View file

@ -14,36 +14,35 @@ using Avalonia.Controls;
using DependencyProperty = Avalonia.AvaloniaProperty;
#endif
namespace MapControl.UiTools
namespace MapControl.UiTools;
public partial class MenuButton : Button
{
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
{
public static readonly DependencyProperty MapProperty =
DependencyPropertyHelper.Register<MenuButton, MapBase>(nameof(Map), null,
async (button, oldValue, newValue) => await button.Initialize());
get => (MapBase)GetValue(MapProperty);
set => SetValue(MapProperty, value);
}
public MapBase Map
private async Task Initialize()
{
if (Map != null)
{
get => (MapBase)GetValue(MapProperty);
set => SetValue(MapProperty, value);
}
DataContext = Map;
private async Task Initialize()
{
if (Map != null)
var initialItem =
Items.OfType<MapMenuItem>().FirstOrDefault(item => item.IsChecked) ??
Items.OfType<MapMenuItem>().FirstOrDefault();
if (initialItem != null)
{
DataContext = Map;
initialItem.IsChecked = true;
var initialItem =
Items.OfType<MapMenuItem>().FirstOrDefault(item => item.IsChecked) ??
Items.OfType<MapMenuItem>().FirstOrDefault();
if (initialItem != null)
{
initialItem.IsChecked = true;
await initialItem.ExecuteAsync(Map);
}
await initialItem.ExecuteAsync(Map);
}
}
}

View file

@ -13,33 +13,32 @@ using Microsoft.UI.Xaml.Data;
using Avalonia.Data.Converters;
#endif
namespace MapControl.UiTools
namespace MapControl.UiTools;
internal partial class ProgressVisibilityConverter : IValueConverter
{
internal partial class ProgressVisibilityConverter : IValueConverter
public object Convert(object value, Type targetType, object parameter, string language)
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var visible = (double)value < 1d;
var visible = (double)value < 1d;
#if AVALONIA
return visible;
return visible;
#else
return visible ? Visibility.Visible : Visibility.Collapsed;
return visible ? Visibility.Visible : Visibility.Collapsed;
#endif
}
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Convert(value, targetType, parameter, culture.ToString());
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Convert(value, targetType, parameter, culture.ToString());
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

View file

@ -2,22 +2,21 @@
using System.Linq;
using System.Windows.Controls;
namespace MapControl.UiTools
namespace MapControl.UiTools;
public partial class MapMenuItem : MenuItem
{
public partial class MapMenuItem : MenuItem
protected MapMenuItem()
{
protected MapMenuItem()
{
Loaded += (_, _) => Initialize();
Click += (_, _) => Execute();
}
public string Text
{
get => Header as string;
set => Header = value;
}
protected IEnumerable<MapMenuItem> ParentMenuItems => ((ItemsControl)Parent).Items.OfType<MapMenuItem>();
Loaded += (_, _) => Initialize();
Click += (_, _) => Execute();
}
public string Text
{
get => Header as string;
set => Header = value;
}
protected IEnumerable<MapMenuItem> ParentMenuItems => ((ItemsControl)Parent).Items.OfType<MapMenuItem>();
}

View file

@ -2,32 +2,31 @@
using System.Windows.Controls;
using System.Windows.Markup;
namespace MapControl.UiTools
namespace MapControl.UiTools;
[ContentProperty(nameof(Items))]
public partial class MenuButton
{
[ContentProperty(nameof(Items))]
public partial class MenuButton
static MenuButton()
{
static MenuButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MenuButton), new FrameworkPropertyMetadata(typeof(MenuButton)));
}
public MenuButton()
{
ContextMenu = new ContextMenu();
DataContextChanged += (_, e) => ContextMenu.DataContext = e.NewValue;
Loaded += async (_, _) => await Initialize();
Click += (_, _) => ContextMenu.IsOpen = true;
}
public string Icon
{
get => Content as string;
set => Content = value;
}
public ContextMenu Menu => ContextMenu;
public ItemCollection Items => ContextMenu.Items;
DefaultStyleKeyProperty.OverrideMetadata(typeof(MenuButton), new FrameworkPropertyMetadata(typeof(MenuButton)));
}
public MenuButton()
{
ContextMenu = new ContextMenu();
DataContextChanged += (_, e) => ContextMenu.DataContext = e.NewValue;
Loaded += async (_, _) => await Initialize();
Click += (_, _) => ContextMenu.IsOpen = true;
}
public string Icon
{
get => Content as string;
set => Content = value;
}
public ContextMenu Menu => ContextMenu;
public ItemCollection Items => ContextMenu.Items;
}

View file

@ -8,21 +8,20 @@ using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
#endif
namespace MapControl.UiTools
namespace MapControl.UiTools;
public abstract partial class MapMenuItem : ToggleMenuFlyoutItem
{
public abstract partial class MapMenuItem : ToggleMenuFlyoutItem
protected MapMenuItem()
{
protected MapMenuItem()
Loaded += (_, _) =>
{
Loaded += (_, _) =>
{
ParentMenuItems = ((Panel)VisualTreeHelper.GetParent(this)).Children.OfType<MapMenuItem>().ToList();
Initialize();
};
ParentMenuItems = ((Panel)VisualTreeHelper.GetParent(this)).Children.OfType<MapMenuItem>().ToList();
Initialize();
};
Click += (_, _) => Execute();
}
protected IList<MapMenuItem> ParentMenuItems { get; private set; }
Click += (_, _) => Execute();
}
protected IList<MapMenuItem> ParentMenuItems { get; private set; }
}

View file

@ -7,25 +7,24 @@ using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Markup;
#endif
namespace MapControl.UiTools
namespace MapControl.UiTools;
[ContentProperty(Name = nameof(Items))]
public partial class MenuButton
{
[ContentProperty(Name = nameof(Items))]
public partial class MenuButton
public MenuButton()
{
public MenuButton()
{
Flyout = new MenuFlyout();
Loaded += async (_, _) => await Initialize();
}
public string Icon
{
get => (Content as FontIcon)?.Glyph;
set => Content = new FontIcon { Glyph = value };
}
public MenuFlyout Menu => (MenuFlyout)Flyout;
public IList<MenuFlyoutItemBase> Items => Menu.Items;
Flyout = new MenuFlyout();
Loaded += async (_, _) => await Initialize();
}
public string Icon
{
get => (Content as FontIcon)?.Glyph;
set => Content = new FontIcon { Glyph = value };
}
public MenuFlyout Menu => (MenuFlyout)Flyout;
public IList<MenuFlyoutItemBase> Items => Menu.Items;
}