Windows 10 1803 上的 RichTextBox 中没有下划线的超链接

Hyperlinks without underline in RichTextBox on Windows 10 1803

我在 RichTextBox("upgraded" 到 RichEdit50W)中显示 RTF 文档。文档中的关键字使用以下语法链接到网页:

{\field{\*\fldinst{HYPERLINK ""https://www.example.com/"" }}{\fldrslt{\cf1 keyword\cf0 }}}

我不想强调关键字。直到 Windows 10 版本 1803(以及 Windows 之前的所有版本,包括 XP、Vista、8),只要在锚点上设置颜色(注意 \cf1),锚点没有下划线。

但这在 Windows 10 版本 1803 中不再有效。我将向 Microsoft 报告此问题。但我不太确定,如果我不依赖于无证行为。我可以想象这个变化实际上不是一个错误,而是一个修复。所以想知道有没有更正确的方法来防止超链接被加下划线

示例代码:

public class ExRichText : RichTextBox
{
    [DllImport("kernel32.dll", EntryPoint = "LoadLibraryW", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern IntPtr LoadLibraryW(string path);

    protected override CreateParams CreateParams
    {
        get
        {
            var cp = base.CreateParams;
            LoadLibraryW("MsftEdit.dll");
            cp.ClassName = "RichEdit50W";
            return cp;
        }
    }
}

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        ExRichText rtb = new ExRichText();
        rtb.Parent = this;
        rtb.SetBounds(10, 10, 200, 100);
        rtb.Rtf = @"{\rtf1 {\colortbl ;\red255\green0\blue0;}bar {\field{\*\fldinst{HYPERLINK ""https://www.example.com/"" }}{\fldrslt{\cf1 link\cf0 }}} bar}";
    }
}

(不需要的)Windows 10 版本 1803 上的结果:

(期望)在 Windows 10 版本 1706 上的结果:

和 Windows 7 上的相同结果:

对于 Windows 8 及更高版本,您可以使用 SendMessage function to send the EM_SETEDITSTYLEEX message to richedit 控件通过为 [=] 指定 SES_EX_HANDLEFRIENDLYURL 来禁用友好 link 的下划线13=] 参数和 wParam` 参数的零。

SES_EX_HANDLEFRIENDLYURL

Display friendly name links with the same text color and underlining as automatic links, provided that temporary formatting isn’t used or uses text autocolor (default: 0).

尽管默认情况下下划线被禁用,但 RichTextBox 控件启用了它。

将以下内容添加到您的 ExRichText class 以提供一种方法 (UnderlineFriendlyLink) 来禁用下划线。

private const Int32 WM_User = 0x400;
private const Int32 EM_SETEDITSTYLEEX = WM_User + 275;
private const Int32 EM_GETEDITSTYLEEX = WM_User + 276;

/// <summary>Display friendly name links with the same text color and underlining as automatic links, provided that temporary formatting isn’t used or uses text autocolor (default: 0)</summary>
private const Int32 SES_EX_HANDLEFRIENDLYURL = 0x100;

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private extern static Int32 SendMessage(HandleRef hWnd, Int32 msg, Int32 wParam, Int32 lParam);

public static void UnderlineFriendlyLink(RichTextBox rtb, bool enabled = false)
{
    if (rtb.IsHandleCreated)
    {
        Int32 wParam = enabled ? SES_EX_HANDLEFRIENDLYURL : 0;
        Int32 lParam = SES_EX_HANDLEFRIENDLYURL; // settings mask
        Int32 res = SendMessage(new HandleRef(null, rtb.Handle), EM_SETEDITSTYLEEX, wParam, lParam);
    }
}

用法示例:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        exRichText1.Rtf = @"{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}{\colortbl ;\red0\green0\blue255;}{\*\generator Riched20 10.0.16299}\viewkind4\uc1 \pard\f0\fs29 Hello {\b{\field{\*\fldinst{HYPERLINK ""http://www.fred.com""}}{\fldrslt{Link}}}}\f0\fs29\par\par https://www.google.com \par\par sd {{\field{\*\fldinst{HYPERLINK ""http://www.fred.com""}}{\fldrslt{klasl}}}}\f0\fs29  wed asdasd \par\par}";
    }

    private void exRichText1_LinkClicked(object sender, LinkClickedEventArgs e)
    {
        System.Diagnostics.Debug.Print(e.LinkText);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        ExRichText.UnderlineFriendlyLink(exRichText1, false);
    }
}

您的 post 没有说明您是如何检测 link 的 单击 的,但请注意,如果您依赖于 LinkClicked 事件如上例所示,由于 RichTextBox CharRangeToString method 中的逻辑错误,事件可能不会触发。特别是这个代码片段。

        //Windows bug: 64-bit windows returns a bad range for us.  VSWhidbey 504502.  
        //Putting in a hack to avoid an unhandled exception.
        if (c.cpMax > Text.Length || c.cpMax-c.cpMin <= 0) {
            return string.Empty;
        }

如果您尝试示例代码,您会注意到该事件仅在第一个 link 时触发。如果 CharRangeToString returns String.Empty,则不会引发该事件。此限制条件使用 Text.Length 属性(例如 58),即 return 是 显示的 长度。我认为它应该改为使用 TextLength 属性(例如 120)。

通过为 EM_Notify 消息监视控件的父级并处理鼠标单击通知,可以在为 x86 或 AnyCPU 编译时使用 CharRange 结构提取 link(首选 32-少量)。当 运行 作为 64 位程序集时,CharRange 结构会 return 无效值,如源代码中所示。


编辑:所有测试都是在 Windows 10 版本 1706 上完成的,因为我现在不会安装 1803。