XAML-Map-Control/MapUiTools/Shared/HyperlinkText.cs

130 lines
3.8 KiB
C#
Raw Normal View History

2025-02-27 18:46:32 +01:00
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
2026-01-12 23:48:17 +01:00
#if WPF
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
#elif WINUI
2021-06-14 21:41:37 +02:00
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Documents;
2021-11-17 23:25:10 +01:00
#elif UWP
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Documents;
2026-04-10 16:55:33 +02:00
#elif AVALONIA
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Media;
using DependencyProperty = Avalonia.AvaloniaProperty;
#endif
2026-04-13 17:14:49 +02:00
namespace MapControl.UiTools;
public static class HyperlinkText
{
2026-04-13 17:14:49 +02:00
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)
{
2026-04-13 17:14:49 +02:00
var inlines = new List<Inline>();
2026-04-13 17:14:49 +02:00
while (!string.IsNullOrEmpty(text))
{
2026-04-13 17:14:49 +02:00
var match = regex.Match(text);
2026-04-13 17:14:49 +02:00
if (match.Success &&
match.Groups.Count == 3 &&
Uri.TryCreate(match.Groups[2].Value, UriKind.Absolute, out Uri uri))
{
2026-04-13 17:14:49 +02:00
inlines.Add(new Run
{
2026-04-13 17:14:49 +02:00
Text = text.Substring(0, match.Index),
2026-04-10 16:55:33 +02:00
#if WPF || AVALONIA
2026-04-13 17:14:49 +02:00
BaselineAlignment = BaselineAlignment.Center
2026-04-10 16:55:33 +02:00
#endif
2026-04-13 17:14:49 +02:00
});
2026-04-10 16:55:33 +02:00
2026-04-13 17:14:49 +02:00
text = text.Substring(match.Index + match.Length);
2026-04-13 17:14:49 +02:00
var hyperlinkText = match.Groups[1].Value;
2026-04-10 16:55:33 +02:00
#if AVALONIA
2026-04-13 17:14:49 +02:00
var button = new HyperlinkButton
{
Content = hyperlinkText,
NavigateUri = uri,
Padding = new Thickness(0),
Margin = new Thickness(0)
};
2026-04-10 16:55:33 +02:00
2026-04-13 17:14:49 +02:00
var link = new InlineUIContainer
{
Child = button,
BaselineAlignment = BaselineAlignment.Center
};
2026-04-10 16:55:33 +02:00
#else
2026-04-13 17:14:49 +02:00
var run = new Run { Text = hyperlinkText };
var link = new Hyperlink { NavigateUri = uri };
link.Inlines.Add(run);
2025-09-16 14:18:29 +02:00
#if WPF
2026-04-13 17:14:49 +02:00
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)
2020-03-20 21:29:43 +01:00
{
2026-04-13 17:14:49 +02:00
Debug.WriteLine($"{e.Uri}: {ex}");
}
};
2026-04-10 16:55:33 +02:00
#endif
#endif
2026-04-13 17:14:49 +02:00
inlines.Add(link);
}
else
{
inlines.Add(new Run { Text = text });
text = null;
}
}
2026-04-13 17:14:49 +02:00
return inlines;
}
public static readonly DependencyProperty InlinesSourceProperty =
DependencyPropertyHelper.RegisterAttached<string>("InlinesSource", typeof(HyperlinkText), null,
(element, oldValue, newValue) =>
{
if (element is TextBlock textBlock)
2026-04-10 16:55:33 +02:00
{
2026-04-13 17:14:49 +02:00
textBlock.Inlines.Clear();
2026-04-10 16:55:33 +02:00
2026-04-13 17:14:49 +02:00
foreach (var inline in TextToInlines(newValue))
{
textBlock.Inlines.Add(inline);
2026-04-10 16:55:33 +02:00
}
2026-04-13 17:14:49 +02:00
}
});
2026-04-13 17:14:49 +02:00
public static string GetInlinesSource(TextBlock element)
{
return (string)element.GetValue(InlinesSourceProperty);
}
2026-04-13 17:14:49 +02:00
public static void SetInlinesSource(TextBlock element, string value)
{
element.SetValue(InlinesSourceProperty, value);
}
}