You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF实现文本内可点击链接的方案咨询(支持多链接场景)

实现WPF消息文本中的可点击链接方案

嘿,这个需求我之前做项目时也碰到过,TextBox本身是纯文本控件,没法直接支持可点击的链接,给你捋两个最实用的方案,还有替代控件的选择:

方案一:用TextBlock(推荐,轻量且原生支持)

TextBlock支持内联元素(比如Hyperlink),是只读场景下的最佳选择。我们可以通过值转换器把绑定的Message文本自动解析成包含普通文本和可点击链接的内联集合。

步骤1:编写链接解析转换器

创建一个实现IValueConverter的类,用正则匹配文本中的链接,然后把文本拆分成普通文本段和Hyperlink段:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;

public class TextToHyperlinkConverter : IValueConverter
{
    // 匹配链接的正则(支持http/https开头,或不带协议的域名)
    private static readonly Regex LinkRegex = new Regex(@"(https?://\S+|www\.\S+|\b[\w-]+\.\w{2,}\b)", RegexOptions.Compiled | RegexOptions.IgnoreCase);

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is not string text || string.IsNullOrEmpty(text))
            return new InlineCollection();

        var inlines = new InlineCollection();
        int lastIndex = 0;

        foreach (Match match in LinkRegex.Matches(text))
        {
            // 添加匹配到的链接之前的普通文本
            if (match.Index > lastIndex)
            {
                inlines.Add(new Run(text.Substring(lastIndex, match.Index - lastIndex))
                {
                    Foreground = Brushes.Black,
                    FontFamily = (FontFamily)Application.Current.FindResource("LatoRegular"),
                    FontSize = (double)Application.Current.FindResource("FontSizeRegular")
                });
            }

            // 处理链接:如果不带协议,自动加上http://
            string linkUrl = match.Value;
            if (!linkUrl.StartsWith("http://") && !linkUrl.StartsWith("https://"))
            {
                linkUrl = $"http://{linkUrl}";
            }

            // 创建可点击的Hyperlink
            var hyperlink = new Hyperlink(new Run(match.Value))
            {
                NavigateUri = new Uri(linkUrl),
                Foreground = Brushes.Blue,
                TextDecorations = TextDecorations.Underline
            };
            hyperlink.Click += (s, e) =>
            {
                var hl = s as Hyperlink;
                if (hl?.NavigateUri != null)
                {
                    // 打开浏览器(.NET Core/.NET 5+需要设置UseShellExecute=true)
                    System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(hl.NavigateUri.ToString())
                    {
                        UseShellExecute = true
                    });
                }
            };

            inlines.Add(hyperlink);
            lastIndex = match.Index + match.Length;
        }

        // 添加最后一段普通文本
        if (lastIndex < text.Length)
        {
            inlines.Add(new Run(text.Substring(lastIndex))
            {
                Foreground = Brushes.Black,
                FontFamily = (FontFamily)Application.Current.FindResource("LatoRegular"),
                FontSize = (double)Application.Current.FindResource("FontSizeRegular")
            });
        }

        return inlines;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

步骤2:在XAML中使用转换器

先在资源中声明转换器,然后绑定TextBlock的Inlines属性:

<Window.Resources>
    <local:TextToHyperlinkConverter x:Key="TextToHyperlinkConverter"/>
</Window.Resources>

<!-- 替换原来的TextBox为TextBlock -->
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" 
           TextWrapping="Wrap" FontFamily="{StaticResource LatoRegular}" 
           FontSize="{StaticResource FontSizeRegular}" 
           Background="Transparent" Padding="0" Margin="0">
    <TextBlock.Inlines>
        <MultiBinding Converter="{StaticResource TextToHyperlinkConverter}">
            <Binding Path="Message"/>
        </MultiBinding>
    </TextBlock.Inlines>
</TextBlock>

方案二:用RichTextBox(适合需要编辑的场景)

如果后续可能需要编辑富文本,可以用RichTextBox。同样通过转换器把文本转换成FlowDocument:

转换器核心代码(简化版)

public class TextToFlowDocumentConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is not string text || string.IsNullOrEmpty(text))
            return new FlowDocument();

        var doc = new FlowDocument();
        var paragraph = new Paragraph();
        // 这里的链接解析逻辑和上面TextBlock的转换器类似,把Inline添加到paragraph.Inlines中
        // ...(复制上面的正则匹配和Hyperlink创建逻辑)
        doc.Blocks.Add(paragraph);
        return doc;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

XAML使用

<RichTextBox VerticalAlignment="Center" HorizontalAlignment="Left" 
             TextWrapping="Wrap" FontFamily="{StaticResource LatoRegular}" 
             FontSize="{StaticResource FontSizeRegular}" 
             Background="Transparent" BorderThickness="0" Padding="0" Margin="0"
             IsReadOnly="True"
             Document="{Binding Message, Converter={StaticResource TextToFlowDocumentConverter}}"/>

其他可选控件

  • 第三方富文本控件:比如MaterialDesignInXamlToolkit中的RichTextBox扩展,或者Telerik的RadRichTextBox,这些控件自带链接识别功能,但需要引入第三方库。
  • 自定义用户控件:如果需要更定制化的样式,可以封装一个包含TextBlock的用户控件,把链接解析逻辑封装进去,方便复用。

内容的提问来源于stack exchange,提问作者user9475328

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:34:57