RichTextBox 中的任意文本链接






4.84/5 (77投票s)
一个扩展的 RichTextBox,允许输入不是以标准协议之一开头的链接。
引言
偶尔,有人会在论坛中询问是否可以将链接添加到 RichTextBox
中,而这些链接不以 http://、ftp:// 或其他“标准”协议开头。
好了,这就是解决方案。
背景
标准的 RichTextBox
有一个非常方便的属性:DetectUrls
。
当设置此属性时,每次 RichTextBox
中的文本更改时,都会解析文本中的 URL,并将匹配的文本范围格式化为链接(默认情况下为下划线、蓝色前景)。
问题是,只有以识别的协议之一(http:、file:、mailto:、ftp:、https:、gopher:、nntp:、prospero:、telnet:、news:、wais:、outlook:)开头的链接才会被识别和重新格式化。当您不想要这种引用时,您会感到束手无策,因为标准的 RichTextBox
完全不允许手动设置链接样式。
幸运的是,.NET 的 RichTextBox
只是 Win32 RichEdit 控件的一个包装器,因此可以通过添加必要的包装器来扩展其功能,以发送 RichEdit 控件所需的各种消息。
RichEdit 控件如何管理样式更改
RichEdit 控件定义了两组消息来控制文本部分的渲染方式。一组(EM_GETCHARFORMAT
、EM_SETCHARFORMAT
)负责设置和查询段落内字符范围的格式选项,另一组(EM_GETPARAFORMAT
、EM_SETPARAFORMAT
)设置/查询整个段落的格式选项(例如对齐方式)。
我们将使用第一组来设置所需的样式。
当您查找 EM_SETCHARFORMAT
的文档时,您会看到一个 CHARFORMAT
结构用于传输格式信息。对于较新版本的 RichEdit 控件(V2.0 及以上版本),该结构扩展为 CHARFORMAT2
struct
,其中包含其他信息。
根据平台 SDK 提供的 CHARFORMAT2
struct
的定义
typedef struct _charformat2 { UINT cbSize; DWORD dwMask; DWORD dwEffects; LONG yHeight; LONG yOffset; COLORREF crTextColor; BYTE bCharSet; BYTE bPitchAndFamily; TCHAR szFaceName[LF_FACESIZE]; WORD wWeight; SHORT sSpacing; COLORREF crBackColor; LCID lcid; DWORD dwReserved; SHORT sStyle; WORD wKerning; BYTE bUnderlineType; BYTE bAnimation; BYTE bRevAuthor; BYTE bReserved1; } CHARFORMAT2;
除其他信息外,还有两个成员控制格式化方面,这些方面可以表示为标志,即文本的某一部分是否设置了此格式属性。这两个成员是 dwMask
和 dwEffects
。dwMask
用于指定您是否要设置/查询给定的格式选项,而 dwEffect
包含实际值。
有一个标志 CFE_LINK
,它正是我们想要的:给文本的一部分设置链接的外观和行为。
包装结构和消息
为了告诉 RichEdit 控件我们想将给定的字符格式分配给文本的一部分,您需要将 Windows 消息 EM_SETCHARFORMAT
发送到控件。如果您对 Win32 struct
具体是如何被包装的以及 SendMessage()
是如何声明的感兴趣,请查看源代码。
重写 struct
声明相当直接,唯一需要稍微考虑的成员是 szFaceName
,因为 C# 的 struct
无法声明为包含指定大小的字符数组。不过,Microsoft 考虑到了这种情况,通过为 MarshalAs
属性提供了 SizeConst
字段。
使用该类
当您使用扩展的 RichTextBox
时,您将有几个新方法可用
public void InsertLink(string text);
public void InsertLink(string text, int position);
在指定位置(如果未指定,则在当前插入位置)插入链接。
如果链接文本不适合作为 LinkClicked
事件的结果(例如,如果您有几个相同的链接文本,您想引用不同的超链接),则还有另外两个方法,您可以在其中指定一个附加的超链接字符串
public void InsertLink(string text, string hyperlink);
public void InsertLink(string text, string hyperlink, int position);
它们的行为与前两个方法相同,但链接文本本身之后,超链接字符串将不可见地添加,并用哈希符号('#')分隔。例如,调用
InsertLink("online help", "myHelpFile.chm");
将在 LinkClickedEventArgs
中得到 "online help#myHelpFile.chm
"。这样,您可以独立管理链接文本和超链接。
设置或清除链接字符格式的基类方法是
public void SetSelectionLink(bool link);
public int GetSelectionLink();
两者都作用于当前选择。GetSelectionLink()
的返回值被设为 int
而不是 bool
,因为当前选择可能包含链接和普通部分,从而产生不一致的结果。这通过返回 -1 来反映,而一致的链接样式则返回 1,一致的非链接样式则返回 0。
注意事项
有一点需要注意。默认情况下,标准 RichTextBox
的 DetectUrls
属性已设置,因此您键入的任何内容都会自动重新格式化。
我的扩展默认关闭此属性,因为它可能会干扰以编程方式添加的链接。当 DetectUrls
属性设置为 true
时,如果您修改了链接旁边的文本,链接格式将丢失。当 DetectUrls
设置为 false
时,这种情况不会发生,因此我建议您保持关闭状态。
可能的扩展
就像我添加了对 CFE_LINK
的支持一样,添加对其他格式标志(例如 CFE_SUBSCRIPT
或 CFE_SUPERSCRIPT
)的支持也应该很轻松,以添加开箱即用的新格式选项。
必要的标志定义已包含在源代码中,这样您就不必再从平台 SDK 中查找它们了。
修改历史
- 02.01.2005
初始发布。
- 03.01.2005
添加了对不可见超链接字符串的支持。