2025-02-27 18:46:32 +01:00
|
|
|
|
using System;
|
2014-10-19 21:50:23 +02:00
|
|
|
|
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
|
2014-12-17 21:38:28 +01:00
|
|
|
|
using Windows.UI.Xaml;
|
|
|
|
|
|
using Windows.UI.Xaml.Controls;
|
2014-10-19 21:50:23 +02:00
|
|
|
|
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;
|
2014-10-19 21:50:23 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
|
2026-04-13 17:14:49 +02:00
|
|
|
|
namespace MapControl.UiTools;
|
|
|
|
|
|
|
|
|
|
|
|
public static class HyperlinkText
|
2014-10-19 21:50:23 +02:00
|
|
|
|
{
|
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)
|
2014-10-19 21:50:23 +02:00
|
|
|
|
{
|
2026-04-13 17:14:49 +02:00
|
|
|
|
var inlines = new List<Inline>();
|
2014-10-19 21:50:23 +02:00
|
|
|
|
|
2026-04-13 17:14:49 +02:00
|
|
|
|
while (!string.IsNullOrEmpty(text))
|
2014-10-19 21:50:23 +02:00
|
|
|
|
{
|
2026-04-13 17:14:49 +02:00
|
|
|
|
var match = regex.Match(text);
|
2014-10-19 21:50:23 +02:00
|
|
|
|
|
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))
|
2014-10-19 21:50:23 +02:00
|
|
|
|
{
|
2026-04-13 17:14:49 +02:00
|
|
|
|
inlines.Add(new Run
|
2014-10-19 21:50:23 +02:00
|
|
|
|
{
|
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);
|
2014-10-19 21:50:23 +02:00
|
|
|
|
|
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
|
2014-10-19 21:50:23 +02:00
|
|
|
|
#endif
|
2026-04-13 17:14:49 +02:00
|
|
|
|
inlines.Add(link);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
inlines.Add(new Run { Text = text });
|
|
|
|
|
|
text = null;
|
2014-10-19 21:50:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2014-12-17 21:38:28 +01:00
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
});
|
2014-12-17 21:38:28 +01:00
|
|
|
|
|
2026-04-13 17:14:49 +02:00
|
|
|
|
public static string GetInlinesSource(TextBlock element)
|
|
|
|
|
|
{
|
|
|
|
|
|
return (string)element.GetValue(InlinesSourceProperty);
|
|
|
|
|
|
}
|
2014-12-17 21:38:28 +01:00
|
|
|
|
|
2026-04-13 17:14:49 +02:00
|
|
|
|
public static void SetInlinesSource(TextBlock element, string value)
|
|
|
|
|
|
{
|
|
|
|
|
|
element.SetValue(InlinesSourceProperty, value);
|
2014-10-19 21:50:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|