65.9K
CodeProject 正在变化。 阅读更多。
Home

Extended Rich Text Box (RichTextBoxEx) 的扩展版本

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (63投票s)

2015年1月23日

CPOL

77分钟阅读

viewsIcon

217802

downloadIcon

23408

我创建了 Razi Syed 创建的 Extended RichTextBox 的增强版本。

注意:重要的近期更改和修复——请参见下文。

Visual Studio 的 RichTextBox 允许许多功能;问题是,宿主程序必须在代码中初始化这些功能。以下控件 RichTextBoxEx 具有工具栏和标尺,允许在单个 WinForms 控件中实现由最终用户发起的复杂功能。下方是 RichTextBoxEx 控件——加上用于启用/禁用自定义链接、自定义选项和拼写检查选项的 CheckBoxes——以及一个多行 TextBox,用于显示主控件的宽度、滚动位置以及任何选定文本的字符代码。该控件还允许宿主程序向其添加其他上下文菜单/工具栏项,此处以“自定义选项”为例——事实上,下方编辑器中最右侧的三个工具栏项是由宿主程序添加的,不是控件本身固有的。

(注意:下载 ZIP 文件后,您应该使用 Windows Explorer 的右键单击“全部提取”选项来手动提取文件夹和文件;AOL 有时在解压缩大文件时存在问题。)

引言

UserControl 是一个 WinForms RichTextBox,添加了 Toolstrip 和 Ruler,允许用户对其执行以下操作(最新更新——2024 年 8 月 20 日下午 3:00 EST)

  1. 设置颜色(前景和背景)、字体属性、文本对齐方式
  2. 查找和替换搜索文本
  3. 拼写检查
  4. 插入图片
  5. 连字符/去连字符
  6. 定义自定义字符和智能字符转换
  7. 保存和加载文本
  8. 打印
  9. 跟踪滚动条信息
  10. 跟踪最近是否进行了更改
  11. 通过标尺设置制表符缩进和制表符
  12. 文本列表(非嵌套的符号列表、编号列表和字母列表)
  13. 插入符号(Unicode 字符)
  14. 可选的“自定义链接”,其中链接具有任意可见文本和隐藏的超文本(链接目标)
  15. 重绘模式设置和智能 RTF 转义和插入
  16. 高级拖放
  17. 皱纹线自动拼写检查(又称“连续拼写检查”)
  18. 向控件的上下文菜单和工具栏添加其他选项——允许通过外部代码向控件添加其他功能,就好像它是“内置”的一样
  19. 可选显示硬分页符为虚线
  20. 使用属性页在设计时设置用户可用的段落列表样式选项
  21. 允许获取/设置段落列表样式、对齐样式(包括完全对齐)和真正的上标/下标/正常样式
  22. 可以设置为显示分页符(在相邻文本行之间显示为虚线)
  23. 支持完全对齐和高级排版,以及真正的上标/下标 (新增!)

此技巧介绍了 RichTextBoxEx 控件——这是由 Razi Syed 创建的“Extended RichTextBox”的增强版本——以及 i00 的拼写检查器,i00 Spell Check and Control Extensions - No Third Party Components Required! (轻微修正和增强版本,包含 EXE 和字典/定义文件)——以及一个用于打印富文本、获取滚动条信息、设置列表样式和处理 RTF(标准或增强控件)的类库,一个专门为富文本框设计的标尺控件,以及一个小型演示程序。最近的更新(从最新开始)如下

  1. 现在 SetPrinterWidthToRightMarginSetRightMarginToPrinterWidth 方法有一个 makeexact 参数,当该参数为 True 时,一个方法会调用另一个方法,以处理近似误差并确保行中断在富文本控件和打印页面上的位置相同(2024 年 8 月 20 日下午 3:00 EST)

  2. AllowHyphenation 属性设置为 False 时,控件现在不允许用户使用 Ctrl + - 插入可选的(音节)连字符。(2023 年 8 月 3 日下午 12:37 EST)

  3. 非常重要!我修复了 RichTextBoxExModule.vbInferHypertextScheme 例程中的一个错误,该错误会导致“live:.cid.xxxxxxx”的 Skype 名称与本地文件名(“驱动器:路径\文件.ext”)混淆。(2023 年 6 月 23 日晚上 8:35 EST)

  4. “插入链接”对话框的上下文菜单现在允许用户追加域名(即“.com”)、前置方案(即“http://”)和/或插入主机头(即“www.”)——每个选项都在单独的子菜单中。(2023 年 6 月 21 日凌晨 1:33 EST)

  5. 底层 RichTextBox 组成控件 rtb 已重命名为 rtbRTB,并被指定为 Friend 而非 Public——同时创建了一个新的只读 Public 属性 rtb,用于返回对 rtbRTB(以前是 rtb)的引用,并允许宿主程序访问富文本框的成员。这不应该破坏任何宿主程序的代码——您不必重命名其中对“rtb”的源代码引用——尽管它将确保对富文本框的引用不能被宿主程序重新分配给另一个 RichTextBox 控件实例。此外,“插入链接”对话框的上下文菜单中的 URL 方案集现在包括“skype:”和“skype:live:.cid.”头,用于将Skype 名称指定为超链接——当 InferURLScheme 为 True 且插入/更新链接(通过编程或用户)时,任何以“live:.cid.”开头的 URL 都会在其前面加上“skype:”方案。(当然,您需要在系统上安装Skype for Desktop才能使用此功能。)(2023 年 6 月 17 日晚上 11:08 EST)

  6. 我做了一些小的改动以减少闪烁并避免不必要的操作(例如,在设置文档使用高级排版格式时选择文档)。(2023 年 3 月 21 日)

  7. 已添加一个新的扩展方法 UseAdvancedTypographyOnText,允许强制对富文本文档应用高级排版——这确保了预先存在的完全对齐文本会如此显示,而不是看起来像左对齐。它已被添加到PrintRichTextBox库(在加载或设置富文本框的 RTF 文本后调用)和RichTextBoxEx控件中相应的PrintRichTextBox.vb文件中,并且该控件在每次使用 LoadFile 方法或设置 Rtf 属性时都会使用。(它也被 SetAlignment 扩展方法使用。)(2023 年 3 月 20 日凌晨 1:20 EST)

  8. 演示图像已更新,以显示完全对齐和真正的上标/下标等功能。(2023 年 3 月 20 日)

  9. 拼写检查器 DLL 已修改,以智能处理隐藏和受保护的文本,因此 RichTextBoxEx 控件不再需要在选择包含自定义链接时执行一系列单独的拼写检查;链接和任何受保护的文本都会被拼写检查工具跳过!(2023 年 3 月 3 日)
  10. 已添加扩展方法以支持完全对齐真正的上标和下标!现在使用真正的脚本样式方法,而不是通过 SelectionCharOffset 进行垂直对齐偏移;为了向后兼容使用旧样式的文档,当对选区使用真实脚本或垂直对齐时,上标/下标的上下文菜单选项仍将被选中。(2023 年 3 月 3 日)请参见下文。
  11. 该控件不再使用 Win32 子类 API 来拦截 WM_PAINT 消息并显示分页符;相反,它使用嵌套在 RichTextBoxEx 类中的类——RTBENativeWindow——该类继承自 NativeWindow 子类类。(2023 年 3 月 3 日)
  12. rtb.ContainsProtectedText 扩展方法仅用于选定文本时,它会逐个字符地检查选区中的受保护文本,前提是 .NET 版本为 4.7 或更高,并且选区包含隐藏文本——以防受保护文本也被隐藏并且 rtb.SelectedRtf 未返回。 (2023 年 3 月 3 日)
  13. 已添加 EnableOrDisableCustomOptions 事件,允许程序员设置已添加到控件上下文菜单和/或工具栏的任何自定义选项的启用/禁用状态。(2023 年 3 月 3 日)
  14. 底层富文本框现在仅在右键单击时显示上下文菜单,前提是 rtb.ReadOnly 设置为 False,因为菜单选项涉及用户触发的更改,而当(子)属性设置为 True 时无法发生这些更改。(2022 年 11 月 13 日凌晨 12:52 EST)

  15. 我修复了 SaveFileLoadFile 方法逻辑中的一个错误,该错误会触发关于格式的异常。(2022 年 11 月 12 日凌晨 12:50 EST)

  16. 添加了一个新属性 AvailableListStyle,允许指定用户是否可以使用工具栏或上下文菜单为选定段落设置某些列表引导符类型(可以启用或禁用项目符号、阿拉伯数字、大写/小写字母和大小写罗马数字;“无引导符”列表始终启用。)已添加属性页编辑器和窗体(在新的文件 ListStyles.vb 中)以在设计时设置此 ListStyleCollection 类型属性。请参见下文控件注释。(2022 年 10 月 12 日)

  17. SetListStyle 不再使用 SendKeys 为选定段落设置特定的列表样式,而是使用 Win32 API。SetListStyle 还允许更多参数来更精细地控制列表段落,现在提供了一个 GetListStyle 扩展方法来检索选定段落的当前样式和其他列表信息。(2022 年 10 月 12 日)

  18. 拼写检查器不再在要拼写检查的区域包含自定义链接时,分别检查该区域的每个非链接部分。相反,它一次性检查整个区域,拼写检查对话框本身会跳过链接和(任何)其他受保护的文本。有关 EXE 库更改的信息,请参见兴趣点。(2022 年 10 月 12 日)

  19. InsertPicture 的图标重载调用 PrintRichTextBox 中的新扩展方法 InsertIcon——该方法将图标插入富文本框,使用当前插入符位置或选区的背景色作为透明色——除非该值为Color.Empty(表示选区中有多个背景色),在这种情况下,使用常规背景色。文件重载将图片文件插入为图标(如果其扩展名为“.ico”),作为图元文件(如果其扩展名为“.wmf”),或作为位图(对于任何其他扩展名)。(2022 年 1 月 31 日)

  20. 控件不再依赖剪贴板将图像插入文档(2022 年 1 月 28 日)!修改源自 Khendys Gordon“Insert Plain Text and Images into RichTextBox at Runtime” 的源代码,并依赖于生成将图像包装在 Windows Metafile 中进行拼写的 RTF 代码——这正是 RichTextBox 控件和 WordPad 在粘贴图像时所做的。此外,InsertPicture 方法不再具有将 Image 转换为 Bitmap 的重载(不再需要;因为 Bitmap 派生自 Image,所以此更改不应破坏任何代码),并且 PrintRichTextBox 类库有一个新方法 InsertImage——允许将图像放入标准 RichTextBox 中——同样,无需使用剪贴板。(InsertPicture 调用 InsertImage。)

  21. 辅助控件类 TextRuler 的事件现在由受保护的可重写“On”方法实现(2021 年 12 月 28 日)。2021 年 12 月初进行了较小的修订。

  22. 我对 i00SpellCheck 库程序进行了修复和改进(2021 年 10 月 17 日),以便拼写检查器在文档/选区包含不可见(但不一定受保护)文本时正确进行替换,并设置主程序中的拼写检查选项,使其跳过文档/选区中的自定义链接文本(为文本中有问题的每个非链接区域调用拼写检查对话框)。我还更改了拼写检查器识别单词边界和数字的机制,使其功能更类似于(但并非完全相同于)Word。
  23. 我已对主富文本框控件进行了子类化(2021 年 10 月 17 日)——使用 SetWindowSubclassRemoveWindowSubclass API——使用嵌套子类类(RTBENativeWindow,继承自 NativeWindow)和一个 Timer 组件(请勿删除!)——这样,在重绘时,任何硬(强制)分页符字符都可以选择性地在相邻页面之间显示为虚线(而不是看起来像普通的回车符)。添加了两个属性来促进此功能,并允许用户选择性地插入硬分页符和行中断字符。
  24. 我已更改手动硬插入左右引号所需的按键组合(2021 年 10 月 17 日),以便必须同时按住 Ctrl和 Alt(加上 Shift 以获得左右双引号字符),以及 [~`] 或 ["'] 键。这是为了避免与预定义的富文本框创建带重音符号和其他变音符号的字符的快捷键冲突。
  25. 我修复了 i00SpellCheck 库中的一个错误(2021 年 8 月 6 日),该错误会在宿主应用程序针对 .NET 4.7 或更高版本时,当用户在富文本框中选择多个单词,然后使用工具栏组合框更改字体名称/大小,然后单击返回到富文本框时,导致应用程序崩溃。
  26. 我已弥补了 .NET 4.7 或更高版本下富文本框的一个错误,该错误会导致在文档中嵌入了“隐藏”(不可见)文本(例如自定义链接)时,错误地定位可见文本。请参见下文。
  27. 现在有了用于包含 BitmapImageIcon 形式的图片的重载方法——以及(预先存在的)文件名选项。
  28. 现在有一个名为 InferURLScheme 的属性,用于告知控件用户或 AddCustomLink 方法在插入的超链接不包含方案时是否推断其方案。此外,还有一个新方法 SelectAnyLinkUnderCaret,如果插入符位于链接上方但尚未高亮显示,则会高亮显示该自定义链接。此方法可选择性地与 IsCaretOverALink 属性一起使用,以确保在链接保护关闭时,链接不会被意外地以句法不正确的方式修改。
  29. 连字符工具现在能够判断一个单词是否已经连字符化,并且不会再将连字符化的单词部分误认为是整个单词。
  30. 现在有一个名为 IsCaretOverALink 的属性,可以用来查看插入符是否跨越了一个自定义链接,然后再进行粘贴(在保护关闭的情况下)。
  31. “删除线”(strike)格式选项现在有一个工具栏按钮(该按钮是其在上下文菜单中条目的图形显示)
  32. 我修改了控件的自定义事件以及内置的 TextChangedDragDrop 事件的自定义链接保护的行为。五个事件现在明确允许宿主程序(临时)关闭和打开链接保护,在宿主程序的事件过程代码中。EditWithLinksUnprotected 方法及其关联的 EditingWithLinksUnprotected 事件——与更新的其他事件不同,它会取消保护所有链接(而不仅仅是您“选择”取消保护的链接)——仍然支持与其他事件一起使用。请参见下文。
  33. 我添加了上下文子菜单选项来设置文本和背景颜色;现在(除用于设置字体和大小的组合框外)所有工具栏功能都可以从上下文菜单中访问。此外,我还更新了工具栏按钮的图形,并将这些图像包含在相应的上下文菜单项中。(演示程序现在为其自定义工具栏项和相应的自定义菜单项提供了图像。)
  34. 我修复了一个小错误,该错误会导致控件在文本框内容以自定义链接结尾且没有尾随“不可见”连字符时崩溃。
  35. 针对 .NET 4.7 或更高版本的宿主程序进行了额外的修改和添加成员,特别是在读取和搜索文本方面。请参见下文。
  36. 有更多的打印选项:可以指定要打印或跳过的单个页面,或者指定在一个页面范围内仅打印奇数或偶数页。
  37. 控件的拖放功能得到了扩展。请参见下文。
  38. 现在可以使用查找/替换对话框覆盖包含链接的文本。请参见下文。
  39. 查找上一个选项(Shift + F3)允许在查找对话框之外,按与上次查找对话框调用指定的相反方向搜索。
  40. 现在使用的是不同的拼写检查器。(我以前使用 Paul Welter 的“NetSpell - Spell Checker for .NET”。)
  41. 现在可以自定义工具栏和上下文菜单,添加其他项。请注意,关于如何支持这一点,已经经历了反复的更改!请参见下文。

特点

此版本的 RichTextBoxEx 相对于 Razi Syed 的版本具有以下增强功能

  1. 工具栏上已添加了背景颜色、斜体、删除线、插入图片查找/替换、查找下一个查找上一个连字符、插入符号以及插入/编辑/移除超链接(当自定义链接启用时)的按钮——以及用于字体和大小的组合框。此外,当控件调整大小时,组成控件——工具栏和文本框——会被调整大小以填充它。
  2. 底层 RichTextBox,“rtb”,被声明为 Public,以便可以访问其属性、方法和事件。只需确保在对象表达式中包含“rtb”。
  3. 底层“rtb”控件的 AllowDrop 属性设置为 True,以便富文本可以轻松地与其他富文本应用程序之间拖放。HideSelection 设置为 False,以便在查找、替换和连字符对话框显示时可以看到选定的文本。ShowSelectionMargin 设置为 True,以便用户可以轻松地选择整行文本。
  4. 为“rtb”控件分配了一个带有快捷键的上下文菜单。
  5. 组成富文本控件的内部 KeyDown 事件定义了多个“自定义字符”——并引发一个事件以允许您定义自己的自定义字符或快捷方式;其内部 KeyPress 事件定义了“智能字符”——并引发一个事件以允许您定义自己的智能字符替换。(查找/替换对话框的文本框现在识别默认的自定义字符按键。)
  6. 有顶层属性用于允许/禁止用户进行拼写检查/项目符号/图片插入/文本插入/智能文本,显示/隐藏工具栏(项的快捷键和任何自定义字符仍然有效),允许/禁止设置文本和在一起——而且,如前所述,一个事件允许自定义按键序列生成 RTF 字符/字符串。
  7. 要搜索文本,请使用查找/替换(Ctrl + F / Ctrl + H)拉出对话框,输入搜索文本、搜索方向(向上或向下),以及是否区分大小写和/或全词匹配。如果在富文本中找到,单词将被选中。如果选择替换,您可以从指定方向的当前位置替换一个或所有匹配项。要退出查找或替换对话框,请按取消(ESC)。要查找并选择相同文本的后续匹配项(使用相同的方向和条件),请使用查找下一个(F3)。要查找并选择之前的匹配项(以相反方向但具有相同条件),请使用查找上一个(Shift + F3)。
  8. 可以添加图片。当选择插入图片按钮(或等效的上下文菜单项)时,文件对话框允许用户选择图片文件。图片将被复制到剪贴板并粘贴到当前插入符位置的控件中(替换任何预先高亮的文本)。
  9. 该控件可以搜索可连字符化的换行文本;当找到这样的单词时,对话框允许您定位断点,并选择连字符化单词、跳过它(保持不变)或退出。(单词必须是一系列字母数字字符,并且有足够的长度/空间,在断开后在第一行末尾留下 2 个或更多字符,在第二行开头留下 3 个或更多字符。)
  10. 该控件可以去连字符化文本:在“连字符”上下文菜单中有用于连字符化文本、删除所有连字符或仅删除“隐藏”连字符(由于文本在其后不换行而未显示的连字符)的选项。
  11. 添加了一个类库,用于促进富文本的打印、文本框滚动条信息的跟踪、列表处理、RTF 处理以及控制器的重绘模式的开关。
  12. 支持自定义链接,这些链接显示任意可见文本并跳转到不可见超链接。
  13. 存在用于保存和加载文本、插入图片以及检查/添加/移除自定义链接的方法。
  14. 可以显示标尺,允许用户设置首行/悬挂/右缩进和制表符。
  15. 列表可以指定为项目符号阿拉伯数字大写/小写罗马数字或大写/小写字母。 (列表不能“嵌套”——即用于大纲。可惜。)
  16. 存在一个对话框,用于查找和插入各种字体中可由可打印 Unicode 字符表示的符号。
  17. 此版本现在使用更增强、更细致的拼写检查器。(但是,在将此控件拖放到窗体上之前,请确保“预先引用”它。)
  18. 宿主程序可以向控件的上下文菜单和工具栏添加其他项,以添加特定于应用程序编辑器功能的其他功能。
  19. 硬分页符字符会在一页的最后一行和下一页的第一行之间产生虚线。(软分页符不显示,因为它们依赖于打印时的PrinterSettings。)

控件注释

开始或加载使用此控件的项目/解决方案后,在处理不使用此控件的项目/解决方案时请注意(请阅读)

如果您正在处理一个不使用此控件的项目/解决方案,并且想加载或创建一个使用此控件的项目,那么请完全退出 Visual Studio,然后重新启动它,然后再加载或创建使用此控件的项目;否则,后面项目中使用了此控件的窗体将无法正确显示!该问题与 ListStyleCollection 类型有关,它用于 AvailableListStyle 属性,继承自 Collection(Of Boolean)——当用于使用该控件的项目/解决方案是 Visual Studio 会话中第一个被加载/创建的项目/解决方案,或者前一个项目/解决方案使用该控件时,它不会出现。(如果您想向不使用此控件的解决方案添加一个使用此控件的项目,则添加/创建额外的项目,确保它引用了该控件(暂时不要将其添加到任何窗体中!),然后退出 Visual Studio 并重新启动它,使用已修改的解决方案。之后,您应该能够将控件添加到窗体中,并使其正常显示。)很抱歉造成任何不便。

在设计时修改“DoCustomLinks”后从窗体中移除控件时请注意

在设计时“剪切”或移除窗体中的此控件之前,请确保在属性窗口中将 DoCustomLinks 设置为 False;否则,尝试移除控件将导致 Visual Studio 环境崩溃并重启!仅当您即将剪切或移除控件时,才在设计时将此属性设置为 True。

宿主应用程序的目标平台为 .NET 4.7 或更高版本时的注意事项(请阅读)

已解决的问题

.NET 4.7 处理 RichTextBox 控件——以及通过此控件——的方式与包含“隐藏”(不可见)文本的文档不同(就我个人而言,我认为是不可靠的并且负面的)(!!),而这正是我控件中“自定义链接”(链接的显示“友好文本”与“超链接”URL 不同)的基础。特别是,底层 RichTextBox 控件的纯文本和字符索引查找成员在文档中存在隐藏文本时不再完全可靠。对于某些成员——特别是 TextSelectedTextSelectionLengthFind——我在 PrintRichTextBox 模块中提供了“变通”的扩展方法,以及一种稍作修改的自定义链接格式。

然而,有一件事我以前一直无法可靠地、更不用说透明地补偿,那就是 RichTextBox 在可靠查找隐藏文本中的链接方面的新困难。我偶然发现——当文档末尾填充了额外的“可见”字符时,即使存在隐藏文本,.NET 4.7+ 中的控件也能可靠地找到并响应可见文本。因此,控件会在实例化时检查 Text 是否返回隐藏文本——如果没有,它会安排这样一种方式:每当文档包含隐藏字符时,将在文档末尾填充等量的“可选”音节连字符(未标记为隐藏但未显示,因为它们不破坏单词)加上 5 个额外的连字符。处理选定的例程确保用户无法将插入符置于其上方或选择包含它们(除非选择了整个文档)。此外,此(表面)控件的 ExtendedTextTextRtf 属性在返回文本时省略任何连字符填充,SaveText 方法在保存文档时省略填充。(然而,组成控件的底层成员会返回或保存填充,所以您不应该在这些成员前面加上“.rtb”,除非您想获取或保存填充!)当宿主环境是 .NET 4.7 之前的平台时,不使用填充,因为在这种情况下,控件默认会正确处理隐藏文本。

此外,我修复了 i00SpellCheck 库中的一个错误,该错误在使用工具栏组合框更改字体名称/大小然后单击返回到文本框时会导致宿主应用程序崩溃。这是当宿主应用程序的目标平台为 .NET 4.7+ 时的一个问题。

尚未解决的问题

RichTextBoxUndoRedo 方法在 .NET 4.7+ 中,在“编程”(非用户)编辑之后会触发无法处理的异常,因此本控件设计为在宿主应用程序的目标平台为 .NET 4.7+ 时不支持撤销/重做。此外,该控件设计为当使用 F3 / Shift + F3 查找文本的下一个/上一个匹配项,并且目标平台为 .NET 4.7+ 时,它只会将插入符移动到找到文本的开头,而不是高亮显示它。(出于某种原因,文本框在执行该选项后希望“大小写修改”已高亮显示的文本!)

在 TabControls 的 TabPages 上使用时的注意事项

如果此 RichTextBoxEx 控件放置在 TabControlTabPage 上,并且在加载/显示窗体时该页面不是初始当前页面,那么当用户显示选项卡页面并激活该控件时(尤其是在第二次),控件的文本框部分可能会发生故障并拒绝(!)鼠标和键盘输入。为了解决这种情况,请在窗体的 LoadActivated 事件中暂时将该选项卡页面设置为当前页面。(如果您在运行时创建 RichTextBoxEx 的实例到选项卡页面上,那么请确保在代码将控件交给最终用户之前暂时选择该选项卡页面。)例如

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
   Dim CurrentTab As TabPage = TabControl1.SelectedTab
   TabControl1.SelectedTab = TabWithRTBEControl 'temporarily select tab with editor
   TabControl1.SelectedTab = CurrentTab 'restore previous tab
End Sub

控件的引用依赖项(请阅读)

要在项目/解决方案中使用 RichTextBoxEx UserControl,您必须先添加对RichTextBoxEx.dll i00SpellCheck.exe(!) 的引用,然后再将控件添加到项目窗体中。(拼写检查器是独立组件,所以您也必须引用它。)确保“References”允许“Copy Local”,以便这两个文件都会被复制到任何项目的启动目录路径,并且当您将控件添加到工具箱(通过“Choose Items”)时,RichTextBoxEx.dll 的源目录应与您在任何项目中引用该控件时将依赖的目录相同。在运行宿主项目之前,您应该保存它,以确保库文件在它的启动路径中,然后您可以将字典(dic.dic)和定义(def.def)文件添加到该目录。如果您省略这些文本文件并仍然调用拼写检查器,程序在运行时不会崩溃,不像早期拼写检查器工具那样——但是,您不会看到拼写错误文本下的皱纹线或在拼写检查对话框/上下文菜单中获得建议。此外,如果您只省略定义文件,在悬停在上面时将显示建议但不会显示定义。就这些文件而言,拼写检查器几乎是用户无法破解的,所以如果您不允许拼写检查,可以省略它们,如果您想要拼写检查但不需要定义,可以只包含字典文件。(但是,即使您不“使用”i00SpellCheck.exe,也请先引用它,否则控件将无法正确加载到窗体上!)

此版本的 RichTextBox.dll 将主控件(RichTextBoxEx)、TextRuler 组成控件和 PrintRichTextBox 库全部集成到一个项目中——消除了对许多引用的需求。

此外,如果您打算在宿主应用程序的代码中使用 PrintRichTextBox 类库的扩展方法,则您需要在任何使用这些方法的代码文件中Import RichTextBoxEx(在使用自定义控件 RichTextBoxEx 时)或Import RichTextBoxEx.PrintRichTextBox(仅在使用普通 RichTextBox 时——在这种情况下,您可以使用PrintRichTextBox.dll代替RichTextBoxEx.dlli00SpellCheck.exe)。(要访问此控件之外的拼写检查器功能,请Import i00SpellCheck。)

每个辅助控件和库——PrintRichTextBoxTextRuleri00SpellCheck——都可以单独使用;要了解如何使用 TextRuler,请参阅作者(也是 Advanced Text Editor with Ruler)的文章General-purpose RULER Control for Use with RICH-TEXT CONTROLS

对 UserControl 本身进行设计时更改(请阅读)

如果在修改控件库项目本身时,在“Error List”窗口中看到 2 条错误消息,例如“TextRuler 不是 RichTextBoxEx 的成员”,只需进入设计器文件 RichTextBoxEx.Designer.vb,从错误语句中的对象表达式中删除“RichTextBoxEx.”(只需单击错误消息即可转到语句),然后保存。(在我显示 UserControl、进行任何设计更改然后打开主代码文件时,这种情况往往会发生;我不知道为什么。这是编辑源代码时的一个小麻烦,但在进行任何设计更改后,您必须进行这些更正,否则库将无法构建!)

自定义链接支持

我现在增加了对链接的支持,这些链接使用任意可见文本,并使用隐藏文本来指示当可见文本被单击时跳转的超文本链接。我从 mav.northwind 的 Links with arbitrary text in a RichTextBox(在链接中嵌入不可见文本以用于超文本目标)和 Israel Sant'Anna 的 AnyLinkRichTextBox 替代方案(文本保护链接并使用列表来跟踪它们(在我的情况下,是 SortedList 而不是 Dictionary))中汲取了灵感。我试图使其简单化,并努力用我自己的版本消除了两者中注意到的许多缺陷;这导致了许多精巧的代码技巧——在 Visual Studio RichTextBox 中实现自定义链接并不容易!我对我实现方法的解释在文章的末尾——我强烈建议在尝试改进或自定义它之前,仔细查看相关代码(特别是名称中包含“CustomLink”的变量/常量/过程/类型,以及 RichTextBoxEx.vb 中的最后几个私有过程)!

成员更改

如果您已在使用此控件,请注意,自我首次创建以来,以下更改:

  1. AllowBullets 属性已被 AllowLists 取代。如果您希望您现有的程序能够运行,甚至在项目窗体上显示(新版本)控件,您必须在所有代码(包括窗体的设计器-代码”文件!)中将所有对“AllowBullets”的引用更改为“AllowLists”。 (只需使用替换文本选项,并将范围设置为“整个解决方案”;或显示错误框并单击关于此的错误以找到并逐个修复过时的语句。)此外,OvertypeMode 已被移除,因此您必须从代码(包括设计器文件)中移除对它的引用。
  2. CustomContextMenuItemsCustomToolStripItems 属性曾短暂地更改为 List(Of ToolStripItem) 类型而不是 ToolStripItemCollection,但现在又变回了 ToolstripItemCollection 类型。我从控件中移除了ToolStripItemList方法,并用GetToolStripItemArray方法取而代之。我添加了 CustomContextMenuArrayCustomToolStripArray 属性,它们与其“xxxItems”对应属性相同,只是它们是 ToolStrip() 类型的数组,而不是 ToolStripItemCollection。尽管这些新属性以及 GetToolStripItemArray 方法有效地消除了对原始属性的需求,但我保留了它们以避免破坏任何人的代码。
  3. 我移除了 AreLinksProtected 属性,并添加了一个新属性 IsCaretOverALink,以允许宿主程序在某些事件中避免在未保护的自定义链接中粘贴。
  4. 新属性 AvailableListStyles 允许设置当 AllowLists 设置为 True 时,是否允许用户为列表中的段落枚举各种列表引导符样式。

底层 RichTextBox 控件的属性、方法和事件

底层 RichTextBox,属性 rtb,被定义为 Public,因此您可以访问其属性、方法和事件。要捕获底层 rtb 的事件,请使用 AddHandlerRemoveHandler 来将过程挂钩到它们;使用 WithEventsHandles 不适用于组成控件!主代码示例的最后一行显示了一个示例。

注意:此控件将不再允许直接从外部更改底层 rtb 控件的 ContextMenuContextMenuStrip 属性。您可以在宿主项目中设置这些属性,但这样做不会产生任何效果。这可以防止文本框的内置上下文菜单被完全抢占,同时允许修改其他属性。请使用CustomContextMenuItemsCustomContextMenuArray 属性来添加或删除菜单项。您可以直接添加或删除项到/从 rtb.ContextMenuStrip 属性的 Items 集合。但是,任何被移除的“内置”选项都将立即重新添加。此外,通过这种方式添加或删除的任何“自定义项”只会添加/删除 CustomToolStripItemClicked 事件支持,并相对于内部 CustomContextMenu() 数组进行添加/删除,前提是该项的Name属性不为 null。(它不再需要已经存在于数组中。)“未命名”项(例如 i00SpellCheck 在允许“连续”拼写检查时在菜单中包含的“建议”)可以直接与 ContextMenuStrip(参见下文)使用 AddHandler 进行事件处理。

拖放操作

当底层富文本框发生自动拖放(rtb.EnableAutoDragDrop = True)时,或者文本框捕获到常规拖放(rtb.AllowDrop = True)时,在外部 UserControl 类的 DragDrop 事件期间,名为 AutoDragDropInProgress 的新属性将为 True——程序员可以在事件的过程中使用它来选择性地阻止在出于其他原因触发该事件时发生的任何自定义拖放操作。如果程序员使用了自定义逻辑但希望其后跟富文本框的自动拖放操作,程序员可以在过程中将 e.Effects 设置为 DragDropEffect.None(别忘了这样做!)。底层文本框捕获的任何 DragEnterDragOverDragLeaveDragOp 事件都会调用 UserControl 类中的相应事件——但自定义链接仅在前面三个事件独立于内部富文本框(即,在工具栏上发生拖放)或当时未按下任何按钮时(注意!)受到保护。链接始终受到 DragDrop 事件的保护——而这个事件通常是进行文本更改的地方。最后,任何试图将信息拖放到自定义链接或包含此类链接的选定文本之上的操作都将被取消;此外,当鼠标按钮按下时,不识别任何按键(除了修饰键,如 [Ctrl])。

自定义上下文菜单和工具栏

现在可以在控件的上下文菜单和工具栏中添加额外的选项,以实现特定于应用程序编辑器的功能。CustomContextMenuItems 和 CustomToolStripItems 属性可以分配给 ToolStripItemCollection 对象,这些对象具有额外的 ToolstripItems。或者,CustomCoxtextMenuArrayCustomToolStripMenuArray 属性分别可以接受 ToolStripItems 的数组。该控件会捕获任何分配项及其子项或后代项的 Click 事件,作为 CustomToolStripItemClicked 事件。这允许添加具有“内置”到编辑器控件外观的附加编辑选项!(例如,处理嵌套下拉 ToolstripItems 的事件,请参阅我的文章 Handling Menus and Toolbars Using MDICommandSupport Class Library。)

要操作 ToolstripItems 的属性和方法以及其他事件,请在您的宿主程序中直接引用这些项。(请注意,直接处理的事件与此控件的 CustomToolStripItemClicked 事件不同,它们不会设置任何自定义链接的保护状态,所以在这些其他事件中进行任意编辑之前,请务必检查 AreLinksProtected 属性。)

理论上,您也可以直接将自定义(非内置)项添加或删除到控件的 ContextMenuStrip 属性的 Items 集合中,并且控件会添加/删除 CustomToolStripItemClicked 事件支持并将项添加到/从 CustomContextMenu() 内部数组——但是,使用 CustomContextMenuItemsCustomContextMenuArray 属性更“安全”(就保证期望结果而言);此外,工具栏只能使用 CustomToolStripItems/CustomToolStripItems 属性进行修改,因此使用后一种方法可以使代码更一致。确保每个 ToolStripItemName属性不为 null

Using the Code

RichTextBoxEx 的属性

* 标记为星号的属性在设计时不可用。

  • InferURLScheme -- 布尔值(默认为 True),用于指示当用户或 AddCustomLink 方法插入新自定义链接且超链接不包含方案时,是否应推断方案。
  • MaintainSelection -- 布尔值(默认为 True),用于指示在替换、连字符、拼写检查或其他文档操作后,是否应将高亮显示恢复到选定文本。
  • IsTextChanged * -- 布尔值,指示自文本保存、加载或最后设置为False以来文本是否已更改(设置为 True 表示假定有更改,设置为 False 表示最近没有更改)。它类似于底层富文本框的Modified属性,不同之处在于,当设置Text属性(或更改Rtf的值)时,它会被设置为 True,并触发ChangesMade事件,而不是在进行“临时”更改(如试用连字符)时。
  • SetColorWithFont -- 布尔值,指示是否可以从字体对话框中设置文本。
  • ShowToolstrip -- 布尔值(默认为 True),指示是否在 RichTextBox 顶部显示 Toolstrip
  • ShowRuler -- 布尔值(默认为 True),指示是否显示用于设置缩进和制表符的标尺。
  • DoCustomLinks -- 布尔值(默认为 False),指示是使用标准的“rtb.DetectUrls”技术处理链接(False)还是使用自定义链接(True)。当此属性为 True 时,请将底层 rtb.DetectUrls 属性设置为 False!
  • KeepHypertextOnRemove -- 布尔值(默认为 False),指示在移除链接时,“不可见”超文本是否应暴露并与自定义链接的主要“可见”文本一起保留;仅当 DoCustomLinks 为 True 时才有意义(且可设置为 True)。
  • AllowTabs -- 布尔值(默认为 True),指示用户是否能够为段落设置制表符(仅当 ShowRuler 为 True 时才有意义)。
  • AllowSpellCheck -- 布尔值(默认为 True),指示控件是否应提供拼写检查功能。
  • AllowDefaultInsertText -- 布尔值(默认为 True),指示控件是否应提供自动默认自定义字符插入以及任何用户定义的插入。
  • AllowDefaultSmartText -- 布尔值(默认为 True),指示控件是否应提供自动默认智能字符替换以及任何用户定义的替换。
  • AllowLists -- 布尔值(默认为 True),指示控件是否应允许列表项目符号(取代 AllowBullets;请参见上面的注意)。
  • AvailableListStyle -- 集合属性(类型为 ListStyleCollection,继承自 Collection(Of Boolean)),用于确定当 AllowLists 为 True 时,用户是否可以为选定段落设置各种列表引导符。使用 RTBListStyle 类型的索引来指定哪个列表样式可以由用户设置/取消设置。(用户始终可以通过编程使用 rtb.SetListStyle. 设置段落样式。)除了 AvailableListStyle(RTBListStyle.NoList) 之外,所有样式都可以启用/禁用,它始终为 True。(用户始终可以拥有未列出的段落。)当除 RTBListList.NoList 之外的样式被启用时,用户可以使用Ctrl + Shift + L 循环遍历可用样式(不可用的样式将被跳过)。
  • AllowHyphenation -- 布尔值(默认为 True),指示控件是否应支持连字符搜索。
  • AllowPictures -- 布尔值(默认为 True),指示控件是否应允许插入图片。
  • AllowSymbols -- 布尔值(默认为 True),指示控件是否应允许使用“插入符号”对话框插入自定义符号。
  • SpellCheckSettings -- i00SpellCheckSpellCheckSettings 实例,包含拼写检查器的设置。您可以按所需方式设置拼写检查选项,但 SpellCheckSettings.AllowF7 将始终由此属性在运行时设置为 False,因为富文本框的上下文菜单已经使用F7 功能键作为快捷方式来调用拼写检查对话框。(要在代码中使用此属性,请Import i00SpellCheck。)当然,只有当拼写检查启用时(即当 AllowSpellCheck = True 时),对此属性的任何更改才能被观察到。
  • UnitsForRuler -- TextRuler.Units 枚举,用于指示标尺是使用英寸(默认)还是厘米(Import RichTextBoxExImport RichTextBoxEx.TextRuler 到任何使用此属性的代码文件中!)。
  • RightMargin -- 文本的最大可打印宽度(rtb.RightMargin);标尺显示会更新以反映更改。
  • FilePath -- 字符串,用于指定文件对话框应该从哪个目录开始(在保存文本、加载文本或插入图片时)。
  • Text -- 文本框的纯文本内容(rtb.Text)的字符串;无论何时设置,IsTextChangedrtb.Modified 都会设置为 True,并始终触发ChangesMade事件。
  • ExtendedText -- 文本框的纯文本内容——包括所有“隐藏文本”——的只读字符串。对于目标平台为 .NET 4.7 之前的宿主程序,它与 Text 相同。
  • Rtf -- 文本框的 RTF 内容(rtb.Rtf)的字符串;仅当新值与现有值不同时,IsTextChangedrtb.Modified 才会被设置,并触发ChangesMade注意:如果您在设置此属性为以自定义链接开头的文本时遇到“保护”错误,那么在设置Rtf之前,请将Text设置为""(空字符串)。(我不知道为什么有时会存在这种异常,更不用说为什么上述技术可以解决它了。)
  • AutoDragDropInProgress * -- 指示底层富文本框是否捕获了拖放(无论是自动拖放还是“允许”的拖放)的只读布尔值;此值仅在 UserControl 的 DragDrop 事件期间为 True
  • SkipLinksOnReplace -- 指示在执行替换操作时,默认情况下是否跳过(True,属性的默认值)或替换(False)与自定义链接重叠的搜索文本匹配项。(最终用户可以在调用对话框时更改此选项。)当自定义链接允许时(DoingCustomLinks 为 True),此值才能设置。当设置为 False 且搜索文本的匹配项包含要替换的链接时,包含这些链接的整个文本将被替换为替换文本。(见下文。)
  • IsSpellCheckingContinuous * -- 布尔值(默认为 True),指示所有无法识别的单词下方是否显示皱纹线,以及当用户在未高亮的单词上右键单击富文本框的上下文菜单时是否包含拼写建议。此“连续拼写检查”模式仅在 AllowSpellCheck 也为 True 时启用。最近的更改:设置 AllowSpellCheck 不再预设此属性的值;此外,我修复了其中的一个错误。(请参见下文的兴趣点。)
  • CustomContextMenuItems * 和 CustomToolstripItems * -- ToolstripItemCollection 对象,用于定义额外的自定义上下文菜单和工具栏选项,其功能由宿主程序定义。集合可以为 Nothing 或为空,以表示没有自定义功能。添加到工具栏的任何项都显示在“内置功能”项的右侧;添加到上下文菜单的任何项都显示在内置功能项下方,以及任何拼写建议上方(当连续拼写检查开启时)。当自定义项或其下拉子项被单击时,会触发 CustomToolStripItemClicked 事件;自定义项的其他事件可以由项本身在外部捕获。
  • CustomContextMenuArray * 和 CustomToolstripArray * -- ToolStrip() 数组,用于定义额外的自定义上下文菜单和工具栏选项,其功能由宿主程序定义。它们与上面两个“xxxItem”属性相同,只是接受和返回 ToolStrip 类型的数组而不是 ToolStripItemCollection。功能工作方式相同。区别在于,数组中的项不必“属于”现有的上下文菜单或工具栏控件。
  • IsCaretOverALink * -- 只读布尔值,指示当没有文本被高亮显示时,插入符是否位于自定义链接内部。当文本被选中(高亮显示)、插入符位于链接外部,或者当自定义链接不允许时(即当 DoCustomLinks 为 False 时),此值始终为 False。
  • ShowPageBreaks -- 布尔值(默认为 True),指示当两行文本被硬分页符字符分隔时,是否应在它们之间显示虚线。(软[非强制]分页符在打印文档时取决于 PrinterSettings,因此不显示。请参见下文的兴趣点。)
  • AllowPageAndLineBreaks -- 布尔值(默认为 True),指示最终用户是否可以插入分页符和(非段落分隔)行中断字符。如果此属性为 False,宿主程序仍然可以通过编程插入此类字符,并且如果 ShowPageBreaks 为 True,编程分页符将显示为虚线。
  • rtb * -- 底层 RichTextBox 组成控件的只读实例,允许访问控件的成员。

注释

  1. 此外,控件内置的 ContextMenuContextMenuStrip 属性在设计时被 Shadowed 并且不可用,以防止通过 CustomContextMenuItems/CustomContextMenuArray 属性以外的方式进行上下文菜单分配。两者都是只读的——ContextMenu 返回 Nothing,而 ContextMenuStrip 返回 rtb.ContextMenuStrip(文本框的菜单)。
  2. 不再提供 AreLinksProtected 属性,因为宿主程序在某些事件期间关闭一个或多个链接保护的能力使其意义不大!!!

RichTextBoxEx 的方法

以下方法——文件方法——可以在任何最终派生自 RichTextBoxEx 的类(控件)中重写。

  • booleanvalue = SaveFile([filename][, format]) -- 将富文本框的内容保存到文件。如果 filenamenull 或省略,则会调用文件对话框,并将 FilePath 作为初始目录。如果 format 被省略,则文件的扩展名决定格式(扩展名为“rtf”则为 RTF,否则为纯文本)。如果成功保存文本,则返回 True,如果对话框被取消,则返回 False。如果成功,则将 IsTextChanged 设置为 False。如果保存为“纯文本”且存在自定义链接,则当 KeepHypertextOnRemove 为 False 时,链接将输出为“visibletext”,当属性为 True 时,则输出为“{visibletext|hyperlink}”。
  • booleanvalue = SaveFile(data, format) -- 将富文本框的内容保存到 IO.Streamdata 是流。此处需要这些参数。其他所有内容与该方法的文件重载相同。此重载始终返回 True。
  • booleanvalue = LoadFile([filename][, format]) -- 将文件的内容加载到富文本框中。如果 filenamenull 或省略,则会调用文件对话框,并将 FilePath 作为初始目录。如果 format 被省略,则文件的扩展名决定格式(扩展名为“rtf”则为 RTF,否则为纯文本)。如果成功加载文本,则返回 True,如果对话框被取消,则返回 False。如果成功,则将 IsTextChanged 设置为 False。
  • booleanvalue = LoadFile(data, format) -- 将 IO.Stream 的内容保存到富文本框中;data 是流。此处需要这些参数。其他所有内容与该方法的文件重载相同。此重载始终返回 True。
  • booleanvalue = InsertPicture([filename]) -- 将文件中的图片插入到富文本框的插入符位置(替换任何选中的文本)。如果 filenamenull 或省略,则会调用文件对话框,并将 FilePath 作为初始目录。如果成功插入图片,则返回 True,如果对话框被取消,则返回 False。如果成功,则将 IsTextChanged 设置为 True,并触发 ChangesMade 事件。根据扩展名是“.ico”、“.wmf”还是其他,图片分别插入为图标、图元文件或位图。
  • booleanvalue = InsertPicture(image|icon) -- 分别将图像(位图或图元文件)或图标插入到富文本框的插入符位置(替换任何选中的文本)。其他所有内容与该方法的文件重载相同。此重载始终返回 True。如果插入图标,则它首先被转换为位图,使用当前插入符位置或选区的背景色作为透明色,除非该值为Color.Empty(表示选区中有多个背景色),在这种情况下,使用 rtb.BackColor

以下方法涉及“自定义链接”,并且仅在自定义链接启用时可执行;如果 DoCustomLinksFalse 且执行了这些方法之一,则会抛出异常。

  • customlinkinfovalue = CheckForCustomLink([position][, lookingbackwards]) -- 检查字符position(默认为当前插入符)是否位于自定义链接上方或其边缘(如果 lookingbackwards 为 True,则为末尾;如果为 False [默认],则为开头)。如果找到,则返回一个 CustomLinkInfo 类实例,其中包含链接的起始位置、(可见)文本和(不可见)超链接;否则,返回 Nothing。
  • booleanvalue = AddCustomLink(customlinkinfovalue) -- 在由 CustomLinkInfo 实例指示的位置插入一个自定义链接,并使用指示的可见文本和超链接文本。成功则返回 True,否则返回 False。如果 CustomLinkInfo 值包含无效信息,则会抛出异常。
  • booleanvalue = RemoveCustomLink(position) -- 删除以指定position开头的自定义链接,将其替换为普通文本(如果 KeepHypertextOnRemove 属性为 True,则为“{visibletext|hyperlinktext}”,否则仅为“visibletext”)。成功则返回 True,否则返回 False。如果position为无效值,则会抛出异常。
  • customlinkinfoarray() = GetCustomLinks([inselectiononly]) -- 返回一个所有自定义链接的数组(如果 inselectiononly = False [默认])或位于插入符处或选中文本中的链接(如果 inselectiononly = True),每个元素都是一个 CustomLinkInfo 实例,包含链接的位置、可见文本和超链接文本。这是链接 SortedListValues 集合,转换为数组;请使用前面的 2 个方法来实际添加或删除链接。
  • SelectAnyLinkUnderCaret-- 检查插入符是否位于自定义链接上方但未高亮显示,如果是,则高亮显示它。
  • EditWithLinksUnprotected([参数]) -- 暂时禁用所有自定义链接的保护,触发 EditingWithLinksUnprotected 事件,然后重新保护链接。此方法在对包含链接的文本进行格式更改时非常有用。参数对象可选地指定将传递给事件过程的信息(任意内容);它按引用传递,以便可以由事件过程修改。(注意:如果在事件过程中发生未处理的异常,链接仍会被重新保护,并且对参数的任何修改仍会传回 给宿主程序。此外,对以下事件所做的更改可能会使此方法变得不必要。)

注意:ToolStripItemList 方法不再受支持,但此新方法取而代之

  • toolstripitems() = GetToolStripItemArray(toolstripitemcollection) -- 接受一个 ToolStripItemCollection 对象,并将其内容转换为 ToolStripItem 类型的数组。如果您想通过添加、删除和/或修改项目,然后通过 CustomContextMenuArrayCustomToolStripArray 将列表添加到控件(分别为上下文菜单或工具栏控件),从而更改菜单或工具栏控件的集合列表(而不影响控件本身的内容),则此方法很有用。

RichTextBoxEx 事件

InsertRtfText -- 允许宿主程序为各种按键定义自定义(RTF)字符或功能。此事件仅应用于指定要插入到插入点/选定文本中的文本,而不是用于进行其他更改——因为在调用时链接保护是开启还是关闭,以及在宿主应用程序的事件过程中是否可以打开和关闭保护,取决于控件的内部状态。(当时)。

输入

  • e.KeyEventArgs -- 有关按键的信息(来自“rtb”的底层 KeyDown 事件)。
  • 输出
    • e.RtfText -- 要插入的自定义文本(或替换选定文本);格式为 RTF,以便程序可以通过 RTF 代码(而不是属性和方法)添加文本框仅支持的功能和字符;null 以允许为预定义的默认按键处理;
    • e.KeyEventArgs.SuppressKeyPress -- 设置为 True 以阻止任何操作或文本插入,即使来自预定义的默认按键。

SmartRtfText -- 允许宿主程序为输入的“纯文本”字符定义智能(RTF)字符替换。此事件仅应用于指定要插入到插入点/选定文本中的文本,而不是用于进行其他更改——因为在调用时链接保护是开启还是关闭,以及在宿主应用程序的事件过程中是否可以打开和关闭保护,取决于控件的内部状态。(当时)。

  • 输入
    • e.KeyPressEventArgs -- 有关按键的信息(来自“rtb”的底层 KeyPress 事件)。
  • 输出
    • e.RtfText -- 要替换输入字符的自定义文本,可能还有插入智能字符之前的字符;格式为 RTF,以便程序可以通过 RTF 代码(而不是属性和方法)添加文本框仅支持的功能和字符;
    • e.PrecedingCharacterCount -- 要在添加智能字符之前删除的现有字符数,这些字符位于输入字符之前。

TextChanged (重写的内置事件) -- 当富文本框发生任何更改时触发。它会盲目地在底层 rtb_TextChanged 事件触发时触发,而不管更改是内部瞬时的还是复合的。仅当您需要立即响应富文本框中的任何更改时才使用此事件。此事件仅应用于更新应用程序的其他方面,而不是文档本身——因为在调用时链接保护是开启还是关闭,以及在宿主应用程序的事件过程中是否可以打开和关闭保护,取决于控件的内部状态。(当时)。

ChangesMade -- 当富文本框的内容发生“重要”更改时触发;它与 TextChanged 的区别在于,当“临时”更改(例如,控件进行试探性断字以确定可以插入连字符的位置)时,它不会触发;当发生“复合”更改时(例如,插入或删除链接,或一般更新链接),它仅在最重要更改之后触发一次。当此事件触发时,IsTextChanged 属性始终为 True。调用时始终会保护链接,并且可以在宿主应用程序的事件过程中打开和关闭任何链接的保护。

TextProtected -- 当用户或宿主程序尝试修改任何受保护的文本(无论是自定义链接还是宿主程序为其他目的而保护的文本)时触发;它与 rtb_Protected 的区别在于,它为宿主程序提供了在事件处理后允许或阻止预定义错误消息发生的选项。调用时始终会保护链接,并且可以在宿主应用程序的事件过程中打开和关闭任何链接的保护。

  • 输出
    • e.Cancel -- True 以跳过退出事件过程后的标准错误警告;False 以允许它。

HyperlinkClicked -- 当用户单击链接(无论是标准的“DetectUrls”链接还是自定义链接)时触发;它与 rtb_LinkClicked 的区别在于,宿主程序会收到一个 CustomLinkInfo 实例,其中包含有关链接的位置、(可见)文本和(不可见)超链接的信息。(注意启用自定义链接时,底层 rtb_LinkClicked 事件(如果捕获到)会在 e.LinkText 中返回“{可见文本|超链接文本}”。)调用时始终会保护链接(自定义链接),并且可以在宿主应用程序的事件过程中打开和关闭任何链接的保护。

  • 输入
    • e.CustomLinkInfo -- 如果启用了自定义链接,则包含有关位置、可见文本和超链接文本的信息;如果未处于自定义链接模式(或链接不是我预定义的自定义链接格式),则位置为 -1,可见/超链接文本都相同。

EditingWithLinksUnprotected -- 允许宿主程序在选定文本包含自定义链接时编辑该文本区域。所有链接的保护将在进入事件时暂时禁用,并在退出事件时恢复。调用时始终会取消保护链接,并且可以在宿主应用程序的事件过程中打开和关闭任何链接的保护。(对其他事件所做的更改可能会使此事件变得不必要。)

  • 输入
    • e.Parameters -- 对象,包含通过 EditWithLinksUnprotected 方法从宿主代码传递到事件过程的信息(任意内容)。
  • 输出
    • e.Parameters -- 对象,包含通过 EditWithLinksUnprotected 方法从事件过程传递回宿主代码的信息(任意内容);即使事件过程中发生未处理的异常,信息仍会成功传回。

CustomToolStripItemClicked -- 当用户单击宿主程序添加的自定义 Toolstrip 项目时触发。调用时始终会保护链接,并且可以在宿主应用程序的事件过程中打开和关闭链接的保护。调用时始终会保护链接,并且可以在宿主应用程序的事件过程中打开和关闭任何链接的保护。

  • 输入
    • e.ClickedItem -- 被单击的 ToolstripItem

DragDrop (重写的内置事件) -- 当有内容被拖放到控件上时触发。在整个事件过程中,链接始终被保持保护状态,除非在宿主应用程序的事件过程中(直接或间接)执行 EditWithLinksUnprotected 方法(及其相关的 EditingWithLinksUnprotected 事件)。

EnableOrDisableCustomOptions -- 当控件需要确定要启用/禁用哪些上下文菜单和工具栏选项时触发,以便程序员能够启用和/或禁用已添加到上下文菜单(使用 CustomContextMenuItems / CustomContextMenuArray)和/或工具栏(使用 CustomToolstripItems / CustomToolstripArray)的任何自定义选项。在标准选项已启用/禁用之后,但在检查哪些选项始终应在文本框标记为只读时禁用的任何检查之前触发。要将用户提供的选项设置为即使在文本框为只读时也仍可启用,请确保相关自定义选项的 ToolstripItem / ToolstripMenuItemTag.ToString以“~aoro(“allowed on read-only”的缩写)结尾!

注释

  1. 与任何其他顶级事件、底层富文本组件控件 rtb 的事件(使用 Addhandler 捕获)以及添加到控件工具栏和上下文菜单的 Toolstrip 项目的事件(参见上面和下面)一样,调用时不会更改自定义链接保护状态,并且在其过程执行期间修改该状态的能力(使用 EditWithLinksUnprotected / EditingWithLinksUnprotected)是不确定的(取决于触发事件的情况)。在单击附加工具栏或自定义菜单的 Toolstrip 项目的情况下,请使用 CustumToolstripItemClicked 而不是工具栏项的本机 Click 事件,以便能够妥善控制链接保护。
  2. 当链接被取消保护时,粘贴文本是安全的,因为文本是高亮的rtb.FullSelectionLength > 0),因为控件确保如果选区包含链接,它将包含完整的链接——所以它们要么完全保留,要么完全删除,但不会被粘贴修改。但是,当没有文本高亮时,当插入点位于未保护的链接上方时进行粘贴可能会损坏它。为避免此情况,请在粘贴前验证IsCaretOverALink在粘贴前返回 False!

ListStyleCollection 类

此类与 AvailableListStyle 属性一起使用,用于确定用户在宿主程序运行时可以设置的段落列表前导符的类型。其构造函数以 RichTextBoxEx 实例作为第一个集合,后跟一个可选的布尔数组或另一个 ListStyleCollection 实例来指定列表样式设置。(默认情况下,所有列表样式均为 True,表示已启用。)集合始终固定为 7 个元素,其中第一个元素(无列表)始终为 True。GetListStyles 方法(或 ToArray)可用于将当前设置获取为布尔数组(索引可以是任何有效的 RTBListStyle 值);SetListStyles 用于将样式设置为布尔数组的值或另一个 ListStyleCollection 实例的设置。默认属性是 Item,其索引指定要启用(设置为 True)或禁用(设置为 False)的列表样式。(任何尝试将 Item(RTBListStyle.NoList) 设置为 False 的操作都将被忽略。)AreAnyAvailable 方法返回除 RTBListStlye.NoList 之外的任何样式是否已启用,Copy 创建并返回当前 ListStyleCollection 对象的重复实例。

PrintRichTextBox 的扩展方法

注意这些方法设计用于标准的 RichTextBox,因此即使您不使用 RichTextBoxEx 控件也能正常工作。(使用 RichTextBoxEx 控件时,请使用其 rtb 属性来引用底层 RichTextBox。在任何使用这些方法的代码文件中,请不要忘记 Import RichTextBoxExImport RichTextBoxEx.PrintRichTextBox!当 UserControl包含在项目中时,只需引用并 Import PrintRichTextBox 即可将独立库与标准控件一起使用。)

打印扩展方法

  • richtextbox.Print(PrintDocument[, whichpages][, pagelist()]) -- 打印文本。whichpages 参数确定是打印 pagelist() 中的页(基于1 的索引)、打印不在 pagelist() 中的页,还是打印范围内的奇数、偶数或所有页,具体取决于PrintDocument 实例的 PrinterSettings.PrintRange 属性(当前插入点所在页、选定文本所在的页、数值范围的页或全部文本)。
  • dialogresult = richtextbox.PrintPreview(PrintPreviewDialog[, whichpages][, pagelist()]) -- 预览文本。预览的内容再次取决于 whichpages,以及 pagelist() 或分配给对话框的 PrintDocumentPrinterSettings.PrintRange 属性。
  • integerarray() = richtextbox.PageIndexes(PrintDocument) -- 返回一个数组,其中包含文本框中每个连续页的起始位置。这可用于确定在哪个页面上会打印什么文本。数组的“页”索引是0 索引的。
  • richtextbox.SetRightMarginToPrinterWidth(PageSettings[, makeexact])(语法新!)-- 设置 richtextbox.RightMargin 属性,以便文本框在与打印页宽度(在左右边距内)相同的水平位置换行。此方法始终将控件的 WordWrap 属性设置为 False。如果包含 makeexact新!)且其值为 True,则还会调用相反的 SetPrinterWidthToRightMargin 方法,以处理近似误差并确保文本框打印页上的换行符完全相同。
  • richtextbox.SetPrinterWidthToRightMargin(PageSettings[, makeexact])(语法新!)-- 设置打印页的右边距,以便它在 richtextbox.RightMargin 属性指示的水平位置换行。这是 SetRightMarginToPageWidth 的反向操作。如果 RightMargin 属性为 0,则不执行任何更改。如果包含 makeexact新!)且其值为 True,则还会调用相反的 SetRightMarginToPrinterWidth 方法,以处理近似误差并确保文本框打印页上的换行符完全相同。

注释

  1. 在使用 SetRightMarginToPrinterWidthSetPrinterWidthToRightMargin 时,您可能需要将 makeexact 设置为 True,以处理近似误差并确保文本框打印页上的换行符完全相同。
  2. 打印或预览时,whichpages 参数是一个 WhichPages 枚举,用于确定要打印的内容
  • PrintSpecifiedPages -- pagelist() 数组中指定的所有页面(忽略 PrinterSettings.PrintRange
  • SkipSpecifiedPages -- pagelist() 数组中未指定的所有页面(忽略 PrinterSettings.PrintRange
  • AllPagesInRange -- PrinterSettings.PrintRange 指定范围内的所有页面(忽略 pagelist()
  • EvenPagesInRange -- PrinterSettings.PrintRange 指定范围内的所有偶数页(“左侧”)页(忽略 pagelist()
  • OddPagesInRange -- PrinterSettings.PrintRange 指定范围内的所有奇数页(“右侧”)页(忽略 pagelist()

滚动条跟踪扩展方法

  • scrollposition = richtextbox.GetScrollPosition() -- 以像素为单位获取当前水平和垂直滚动条位置,结果存储在 System.Drawing.Point 结构中。
  • richtextbox.SetScrollPosition(scrollposition) -- 将水平和垂直滚动条设置为 System.Drawing.Point 结构中指定的像素位置。
  • scrollinfo = richtextbox.GetScrollBarInfo(type[, mask]) -- 以 PrintRichTextBox.ScrollInfo 结构返回滚动条的范围、页面大小、位置和/或轨道位置信息。type 是一个 PrintRichTextBox.ScrollBarType 枚举值,指定 HorizontalVerticalmask 是一个可选的位标志 PrintRichTextBox.ScrollBarMask 枚举值,指定要检索的参数(默认情况下,检索所有 4 项)。
  • textwidth = richtextbox.GetMaximumWidth() -- 以像素为单位获取任何文本的最大水平宽度。如果控件的 RightMargin 属性非零,则使用该属性;否则,如果 WordWrap 为 True,则使用控件的客户端区域宽度;否则,使用最宽行的宽度。它还会考虑 ShowSelectionMargin 是 True 还是 False。

列表制作扩展方法

  • richtextbox.SetListStyle(liststyle[, startingnumber][, numberingsyntax][, indentation])(语法和行为)-- 将富文本框中选定的文本设置为指定的样式;liststyle 是一个 PrintRichTextBox.RTBListStyle 枚举值,指定无列表、项目符号、阿拉伯数字、小写字母、大写字母、小写罗马数字或大写罗马数字作为项目标题。startingnumber(默认为“1”、“a”、“A”、“i”或“I”,具体取决于 liststyle)表示具有指定样式的列表开头的初始前导值。numberingsyntax 是一个 RTBNumberingSyntax 值,指示前导符是否被括号包围(例如,“(1)”),后跟右括号(例如,“1)”),后跟句点(默认;例如,“1.”),或不带符号(例如,“1”)。indentation 指定段落“主体”(前导符之后)与其左侧前导符边缘的缩进像素数;默认情况下,使用所需的最小值为。
  • liststyle = richtextbox.GetListStyle([startingnumber][, numberingsyntax][, indentation]) -- 以 RTBListStyle 枚举值的形式检索富文本框中选定文本开头段落的段落列表样式。可选参数startingnumbernumberingsyntaxindentation 的含义与 SetListStyle 相同;--如果包含,则这些参数应为变量(!!),因为文本框中选定文本开头的这些值将通过引用传递给宿主程序。注意:startingnumber 是列表中第一个段落的第一个段落的样式值,即使该样式列表在选定段落之前开始。也就是说,如果选区从列表的中间(而不是开头)的段落开始,因此富文本框需要回溯到更早的段落才能找到最近一次注意到的样式开始,那么将返回该段落的枚举值,而不是第一个选定段落的枚举值。

对齐和上标/下标处理的扩展方法

  • richtextbox.SetAlignment(alignment) -- 将选定文本的对齐方式设置为 RTBAlginment 枚举值,用于左对齐、右对齐、居中对齐或两端对齐(文本与左右边距都对齐)。这与设置 SelectionAlignment 属性相同,只是它还可以设置两端对齐。
  • alignment = richtextbox.GetAlignment() -- 以 RTBAlignment 枚举值的形式检索插入点处的文本对齐方式(左对齐、右对齐、居中对齐或两端对齐);如果文本已高亮且对齐方式不同,则返回第一个选定段落的对齐方式,而不是 SelectionAlignment 属性的值(在这种情况下,该属性将始终为左对齐的值)。
  • richtextbox.UseAdvancedTypographyOnText() -- 告知富文本框在显示文本时使用高级排版。此方法在设置或加载包含两端对齐文本的 RTF 文本后非常有用,因为新加载或设置的 RTF 文本默认会将两端对齐文本显示为左对齐。当前选区和滚动位置将被保存,使用高级排版选项重新格式化整个文本,然后恢复选区和滚动位置。注意:虽然应该在使用 LoadFile 或设置 Rtf(用于常规 RichTextBox)后使用此方法,但当使用 RichTextBoxEx 控件处理这些方法和属性时(除非您使用的是 rtb.LoadFile 而不是 LoadFilertb.Rtf 而不是 Rtf),则无需这样做,因为上述扩展控件的成员在加载或设置文本时会自动调用此方法。  SetAlignment 扩展方法会将文本框设置为使用高级排版。
  • richtextbox.SetScriptStyle(scriptstyle) -- 将选定文本的上标/下标/常规状态设置为 RTBScriptStyle 枚举值。(任何正值表示上标,任何负值表示下标,0 表示常规。)RichTextBoxEx 控件的上标/下标开启/关闭上下文菜单选项现在使用此方法,而不是 SelectionCharOffset 属性,将文本设置为真正的上标/下标,而不是简单地在垂直方向上调整选定文本;为了向后兼容使用旧方式设置的脚本样式文档,“选定”菜单选项的状态将取决于 GetScriptStyle 方法(如下)返回的值以及 SelectionCharOffset 的值(如果 GetScriptStyle 返回 RTBScriptStyle.Normal,则会查看 SelectionCharOffset)。
  • scriptstyle = richtextbox.GetScriptStyle() -- 以 RTBScriptSyle 枚举值的形式检索插入点处的文本是上标、下标还是常规样式。如果文本已高亮且选定文本的脚本样式混合,则返回插入点处的样式(取决于选区的方向,为选区的开头或结尾)。

处理富文本格式字符串的扩展方法

  • escapedstring = richtextbox.EscapedRtfText(plaintext) -- 将纯文本字符串转换为 RTF 格式,转义任何特殊字符(即“\”、“{”、“}”或非 ANSI 字符)。
  • richtextbox.InsertRtf(rtftext[, position]) -- 在给定位置(默认为当前选区)插入 RTF,并包含任何必要的包装 RTF 以使插入的文本“安全”。这比仅仅将 richtextbox.SelectedRtf 设置为任意文本要好,因为它确保编辑器不会对插入做出不可预测的反应。

处理纯文本的扩展方法(当宿主应用程序的目标平台为 .NET 4.7 或更高版本时)(使用反射访问私有的 RichTextBox 成员 WindowTextcurSelStartcurSelEnd

  • length = richtextbox.FullSelectionLength -- 选定文本的总长度,包括任何隐藏文本。对于以早期平台为目标的项目,这与 SelectionLength 相同。(使用该标准属性来设置选区的长度。)
  • text = richtextbox.ExtendedText[(selectiononly)] -- 当前选区(selectiononly = True)或整个文档(selectiononly = False 或省略)的完整文本,包括任何隐藏文本。对于以早期平台为目标的项目,这分别等于 SelectedTextText。(使用标准属性来设置文本。)
  • position = richtextbox.ExtendedFind(seachtext[, startpos][, endpos][, options]) -- 在文本框中查找 seachtext,其中 startpos(默认为 SelectionStart)指定搜索的起始点(如果省略 endpos)或搜索范围的起始点(如果包含 endpos 来指定范围的结束点)。options(默认为 RichTextBoxFinds.None)是一个 RichTextBoxFinds 枚举,指定搜索方向、匹配标准和查找时的突出显示状态。这与标准的 Find 方法相同,只是在以 .NET 4.7+ 为目标的项目中,它能正确处理任何隐藏文本。
  • position = richtextbox.ExtendedFind(searchchars()[, startpos][, endpos][, reverse]) -- 查找 searchchars() 中的任何字符的第一个。其他属性与此方法的搜索字符串重载行为相同,只是 reverse 为 True 表示向搜索,False(默认)表示向前搜索——这是标准 Find 方法在搜索字符时提供的选项。与前一个重载一样,即使程序以 .NET 4.7+ 为目标,此方法也能正确处理任何隐藏文本。
检查受保护或隐藏(不可见)文本的扩展方法
  • booleanvalue = richtextbox.ContainsProtectedText[(selectiononly)] -- 如果当前选区(selectiononly = True)或整个文档(selectiononly = False 或省略)中任何文本受到保护,则返回 True。这与 SelectionProtected 不同,后者属性始终应用于选区,并且仅在所有选定文本都受保护时返回 True。
  • booleanvalue = richtextbox.ContainsHiddenText[(selectiononly)] -- 如果当前选区(selectiononly = True)或整个文档(selectiononly = False 或省略)中任何文本被标记为不可见,则返回 True。(如果 SelectedRtf/Rtf 中找不到“\v”标签,则将 SelectionLength/Text.LengthFullSelectionLength/ExtendedText.Length 进行比较,以防 .NET 平台为 4.7 或更高版本且不可见文本未在 RTF 中返回。)

插入图像到文档的扩展方法

  • richtextbox.InsertImage(image[, position]) -- 在文档的给定位置(默认为当前选区)插入图像依赖剪贴板;将生成 RTF 代码以将图像包装在 Windows 元文件中进行插入。
  • richtextbox.InsertIcon(icon[, position]) -- 在文档的给定位置(默认为当前选区)插入图标,不依赖剪贴板;图标将被转换为位图,然后生成 RTF 代码以将图标包装在 Windows 元文件中进行插入。图标的透明色取自richtextbox.SelectionBackColor,除非它是Color.Empty(表示选区中存在多种背景色),在这种情况下,使用richtextbox.BackColor

启用/禁用任何控件重绘的扩展方法

  • control.SetRedrawMode(onoroff) -- 打开(True)或关闭(False)控件(任何控件,不仅仅是这里的 RichTextBox)的自动重绘。将其关闭可以进行多次更改而用户看不到中间效果;再次将其打开将强制绘制累积效果。

下面提供了一些代码示例

Imports RichTextBoxEx
Imports RichTextBoxEx.PrintRichTextBox
Imports RichTextBoxEx.TextRulerControl

'   using a property or method

RichTextBoxEx1.AllowSpellCheck = True : RichTextBoxEx1.IsSpellCheckContinuous = False
RichTextBoxEx1.UnitsForRuler = TextRuler.Inches
Dim AutoDrag As Boolean = RichTextBoxEx1.AutoDragDropInProgress
RichTextBoxEx1.CustomContextMenuItems = ContextMenuStrip1.Items
Dim ArrayOfItems() As ToolstripItem = RichTextBoxEx1.GetToolStripItemArray(ToolStrip1.Items)
RichTextBoxEx.CustonToolstripArray = ArrayOfItems
RichTextBoxEx1.SaveFile("My Text.rtf")

RichTextBoxEx1.DoCustomLinks = True
Dim CustomLinkInfo As CustomLinkInfo = _
   New CustomLinkInfo With {.Position = 55, _
      .Text = "Google Maps", .Hyperlink = "http://www.google.com/maps"}
RichTextBox1.AddCustomLink(CustomLinkInfo)

With RichTextBox1
   .AllowLists = True
   .AvailableListStyle(RTBListStyle.Bullets) = False
   .AvailableListStyle(RTBListStyle.Numbers) = True
   .AvailableListStyle(RTBListStyle.LowercaseLetters) = True
   .AvailableListStyle(RTBListStyle.UppercaseLetters) = False
   .AvailableListStyle(RTBListStyle.LowercaseRomanNumerals) = False
   .AvailableListStyle(RTBListSTyle.UppercaseRomanNumerals) = True
End With

'   using extension methods on underlying text box

Dim ScrollPosition As Point = RichTextBoxEx1.rtb.GetScrollPosition()

RichTextBoxEx1.rtb.SetRightMarginToPageWidth(PrintDocument1.DefaultPageSettings)
RichTextBoxEx1.rtb.Print(PrintDocument1)

Dim Pages() As Integer = RichTextBoxEx1.rtb.PageIndexes(PrintDocument1)
RichTextBoxEx1.rtb.Select(Pages(2), Pages(3) - Pages(2)) ' select page (third page)

RichTextBoxEx1.rtb.SetListStyle(RTBListStyle.LowercaseLetters) 'list as a, b, c, ...
Dim StartingNumber, Indentation As Integer, _
   NumberingSyntax As RTBNumberingSyntax
Dim ListStyle As RTBListStyle = _
   RichTextBoxEx1.rtb.GetListStyle(StartingNumber, NumberingSyntax, Indentation)
RichTextBoxEx1.rtb.SetAlignment(RTBAlignment.Full)
RichTextBoxEx1.rtb.SetScriptStyle(RTBScriptStyle.Subscript)

'   catching events

AddHandler RichTextBoxEx1.InsertRtfText, AddressOf RichTextBoxEx1_InsertRtfText
AddHandler RichTextBoxEx1.HyoerlinkClicked, AddressOf RichTextBoxEx1_HyperlinkClicked

AddHandler RichTextBoxEx1.rtb.DoubleClick, _
   AddressOf RTB_DoubleClick ' event for UNDERLYING text box

快捷键的定义方式类似于 Word。例如,Ctrl + X 是剪切,Ctrl + I 是斜体,Ctrl + F 是查找,Ctrl + H 是替换,F3 是查找下一个,Shift + F3 是查找上一个,F7 是拼写检查,依此类推。只需单击控件的 constituent component,ctmRTB即可查看所有内容。(在运行时,当然可以通过右键单击文本框来调用菜单。如果显示了标尺,则用户可以通过右键单击标尺来显示其菜单,从而在英寸和厘米之间切换,)

至于预定义的自定义字符(当 AllowDefaultInsertTextTrue 时),以下是按键列表

字符 按键序列

可选(音节)连字符
(- ; 仅在换行时显示
一个词的末尾)

Ctrl + -

长破折号(—)

Ctrl + Alt + -

短破折号(–)

Ctrl + Alt + Shift + -
省略号(…) Ctrl + Alt + .

左单引号(‘)

Ctrl + Alt + `

左双引号(“)

Ctrl + Alt + Shift + ~

右单引号(’)1

Ctrl + Alt + '

右双引号(”)

Ctrl + Alt + Shift + "

版权符号(©)

Ctrl + Alt + C

注册商标符号(®)

Ctrl + Alt + R

商标符号(™)

Ctrl + Alt + T

换行(非段落)
中断2

Shift + Enter
分页符2 Ctrl + Enter

这些自定义字符按键(除了硬换行符和分页符)也可以用于查找/替换对话框中指定特殊的搜索和/或替换文本,现在也可以用于插入链接对话框中的可见文本和超链接文本;但是,您无法自定义它们的值,添加额外的自定义字符,或在那里指定“特殊操作”,就像您为主控件所做的那样。

至于默认智能字符转换(当 AllowDefaultSmartTextTrue 时)

  1. 常规双引号("),在输入时,如果出现在行首,或出现在空格、常规短横线、短破折号、长破折号、制表符或左单引号之后,则会变为双引号(“);否则,它会变为双引号(”)。
  2. 常规单引号('),在输入时,如果出现在行首,或出现在空格、常规短横线、短破折号、长破折号、制表符或左双引号之后,则会变为单引号(‘);否则,它会变为单引号(’)。
  3. 常规短横线(-),在输入时紧跟在现有常规短横线之后,将被替换(连同其前面的短横线)为长破折号(—)。
  4. 句点(.),在输入时紧跟在 2 个连续句点之后,将被替换(连同其前面的 2 个句点)为省略号(…)。

注释

1由于这不再仅仅是 Ctrl + ',因此当 AllowDefaultSmartText 为 False 时,最终用户现在可以使用 Ctrl + ' 手动切换“智能引号”。(当 AllowDefaultSmartText 为 True 时,引号始终是“智能”的。)

2在查找/替换中不支持,或在 AllowPageAndLineBreaks 为 False 时不支持。

演示程序

功能包括以下内容

字符 按键序列

四分之一(¼)

Ctrl + 4

二分之一(½)

Ctrl + 2

四分之三(¾)

Ctrl + 3

开始新页面

(与 Ctrl + Enter 相同)

Ctrl + Shift + Enter

将选定文本的大小增加 1 点 Ctrl + .
将选定文本的大小减小 1 点 Ctrl + ,
将选定文本大小加倍 Ctrl + Shift + >
将选定文本大小减半 Ctrl + Shift + <

该程序还会将输入的“1/4”、“1/2”、“3/4”分别转换为“¼”、“½”和“¾”。

EditWithLinksUnprotected 方法及其相关的 EditingWithLinksUnprotected 事件用于允许用户使用简单的按键(参见上方列表的最后 4 项)调整选定文本的大小。

程序在演示程序开始时调用页面设置对话框,允许设置页面大小和边距。它还提供复选框来启用/禁用 RichTextBoxEx 控件的自定义链接和插入图片功能,并在一个(垂直可滚动)标准 TextBox 中显示 RichTextBoxEx选定文本的 UTF-32 Unicode 值——这对于确定*哪些字符代码在 RichTextBox 中*做什么*很有用——并显示文本框的当前滚动位置。双击文本框时,程序会调用打印对话框,然后是打印预览和打印。此外,退出应用程序时,会给用户一个选项来保存已修改的文本。

请注意复选框:该程序还允许您在标准的“DetectUrls”链接和自定义链接之间切换。如果单击了链接,系统会询问您是否要调用您为该链接创建的超链接目标所指示的过程。它还允许您打开和关闭常规拼写检查和连续拼写检查。最后,它允许您添加或删除允许您另存为Ctrl + S)、打开(加载)(Ctrl + O)或打印Ctrl + P)文本的自定义上下文菜单/工具栏项。(后一个选项,就像双击编辑器一样,调用 PrintDialog,然后是 PrintPreview,然后打印。另存为打开选项是工具栏中的顶级项目,但在上下文菜单的文件选项下是子菜单项。)

拖放:该程序还允许从其他富文本控件/编辑器以及从(常规)文本框(显示滚动条和字符信息)进行拖放。(请注意,如果源是另一个富文本控件/编辑器,并且要拖放的文本是多格式的,则仅当拖放发生在控件的富文本框部分时,格式才会复制;如果拖放到工具栏上,则以纯文本形式复制。)

关注点

  1. 拼写检查工具现在设计为跳过隐藏和受保护的文本,包括自定义链接。请参阅 i00SpellCheckArticle 的“文本更改和推荐更改的一些问题”帖子(作者:Robert Gustafson),尤其是我的自回复帖子“其他推荐的更改(针对 RichTextBox-es)”(以及该帖子的自回复!),以了解我对i00SpellCheck 项目所做的更改(您只需要在单独下载拼写检查工具时查找它,从其文章而不是本文档中。在这种情况下——也就是说,如果您自己进行更改——请务必生成修改后的项目,以便当前的ii00SpellCheck.dll 包含它们!)以前,此程序会找到文本中的所有链接进行拼写检查,并为每个非链接区域单独调用拼写检查对话框——当文本包含多个链接时,这看起来很尴尬。现在,整个文本或整个选定文本通过一次调用对话框来处理。在拼写检查 EXE 本身中包含对不可更改文本的检查的优点是,它现在也跳过了宿主程序因其他原因而保护的非链接文本。请注意,当单词完全或部分受保护和/或隐藏时,上下文菜单也不会显示文本替换选项,尽管当启用连续拼写检查时,仍然会在“拼写错误”的文本(即链接)下方显示波浪线。(我本可以也提前处理这一点,但这会大大减慢富文本渲染速度。)
  2. 仅为硬分页符显示虚线。要显示*软*分页符的线条,需要修改控件以添加一个额外的属性,该属性分配一个 PrinterSettings 值,然后在 DrawPageBreaks 过程中使用扩展方法 rtb.PageIndexes 来查找所有分页符的字符索引(数组中的除第一个索引外的所有索引),每当文本框重绘或 PrinterSettings-value 属性更改时。请注意,如果文档非常长,则查找和显示软分页符可能会减慢视觉性能!此外,由于硬分页符线条应与软分页符不同,因此对于每个页面索引(以及文本末尾),检查前一个字符是否为换页符(硬分页符)字符。
  3. 断字工具现在可以识别单词是否已断字,并查找完整单词的开头,而不是仅查找最后一个连字符后面的部分。这一点,加上对 i00SpellChecker 的推荐更改,确保了在更新断字或进行拼写检查之前“取消断字”区域的文本不再是首选。断字工具将显示文本框中的任何预先存在的连字符(不在“断字词”预览中),并在确定单词是否可以断字时也将其考虑在内。(设置新连字符时,预先存在的连字符将保持不变;但是,它不会让您将新连字符放在现有连字符的前面或后面——这在这种情况下毫无意义,因为单词在那里已经被断字了。)
  4. 自定义链接现在有一个可选的/音节连字符,位于链接信息的前面后面,以确保当宿主程序以 .NET 4.7+ 为目标时,选择过程能够正确包含整个链接。不用担心早期的 RTF 文件保存没有尾随连字符;控件会在加载文件时自动为任何链接添加它(以及任何丢失的前导连字符)。应指出的是,底层 RichTextBox 控件的 SelectedRtf 属性有时会返回不同的信息,具体取决于宿主的目标平台是 .NET 4.7 还是更早。(`Rtf` 属性没有问题。)
  5. CustomLinkInfo 类型中的 Position 属性现在指向自定义链接的前导连字符,而不是链接本身。这将字符索引减少了 1。
  6. 我使用只读版本阴影化RichTextBoxExContextMenuContextMenuStrip 属性,它们在设计时不可用。这可以防止控件拥有除标尺和富文本框的底层控件定义的上下文菜单之外的任何上下文菜单,后者的菜单可以使用 CustomContextMenuItems/CustomContextMenuArray 属性进行增强。我还配置了底层文本框,以“忽略”( preempt)完全替换其上下文菜单的尝试,而不是仅仅通过上述属性添加其他项目——当 rtb_ContextMenuChangedrtb_ContextMenuStripChanged 事件触发时,它会将其切换回。当菜单被“直接”修改或打开带有下拉子项的项目时,控件还尝试同步对 CustomToolStripItemClicked 事件的正确支持,以防程序员绕过首选属性。
  7. 我修复了一个菜单处理错误:我最初希望允许此控件拥有使用 List(Of ToolstripItem) 类型来获取和返回 ToolStripItem 组的属性,但这在尝试将控件添加到宿主项目时会导致“序列化”错误。我现在改用 ToolStrip() 数组,使用 CustomContextMenuArrayCustomToolStripArray 属性。相关的 ToolStripItemCollection 类型属性被保留以兼容旧版本,它们只是在内部使用的数组版本之间进行转换。
  8. 我修复了 IsSpellCheckContinuous 属性的一个错误。以前,如果您希望控件启动时允许拼写检查但不“连续”-AllowSpellCheck 设置为 True 且 IsSpellCheckContinuous 设置为 False——您需要要么在窗体加载时连续两次将后者属性设置为 False,要么等到窗体句柄创建后再设置它;否则,即使属性返回 False,连续拼写检查仍然启用。这种异常不再发生。如果您在窗体的 Load 事件中只需将 IsSpellCheckContinuous 设置为 False 一次,连续拼写检查将按预期禁用。(注意:在自定义控件中使用 i00SpellCheck 很棘手,因为它需要检查控件的容器窗体是否具有句柄——这最初并不保证,尤其是当控件与窗体一起加载时。此外,在控件处理之前,控件必须禁用任何使用它的文本框的 i00SpellCheck 拼写检查器,以免在控件被移除或项目关闭时抛出异常。)
  9. 我修复了另一个错误,该错误导致控件将i00SpellCheck 开启了窗体上所有文本框相关控件的连续拼写检查,而不仅仅是此控件。现在它只影响此控件的实例。
  10. 查找/替换断字插入符号拼写检查插入链接对话框是模态实现的,以便更好地控制任何选定文本并简化我的编码。(按取消[Esc] 退出查找或替换对话框,或提前退出断字。除插入链接外,用于这些功能和其他功能的文本范围是整个文本,除非高亮显示了某个区域,在这种情况下,仅处理选定的文本。替换、断字和大多数其他修改功能将在 MaintainSelectionTrue 时恢复高亮显示;查找(以及简单查找的最后一个操作的查找/替换)和拼写检查则不。通过 Ctrl + F 调用查找会显示一个“仅查找”对话框(无替换选项)。最后,查找下一个(F3)和查找上一个(Shift + F3)仅限于高亮显示的文本;它们会搜索整个文本以查找后续/上一个出现。当“插入链接”对话框的“超链接”文本框中的文本尚未以方案或“www.”开头时,该文本框有一个上下文菜单,从中可以选择各种前导文本添加到现有文本中“插入链接”对话框的超链接文本框有一个上下文菜单,其子菜单允许您追加域名、前置方案和/或插入主机标头(新!);此外,当您在没有方案的情况下离开对话框时,该对话框会提供一个机会来预先添加一个被认为适合超文本性质的方案。
  11. 现在有一个控件的标尺栏,解释它的文章链接在上面的“依赖关系”部分。
  12. 我修复了偶尔在工具栏中的组合框中使用字体名称和大小设置字体时导致事件级联的错误。关键在于 SettingFont 布尔值,它允许事件防止重复设置字体或组合框条目。将其视为一份圣诞礼物(发布于 2018 年 12 月 25 日)!
  13. 使用自定义链接时,请注意,虽然超链接和分隔符字符的隐藏文本不会在文本框中显示,但它仍然“可见”于其文本处理属性——不仅是 Rtf/rtb.Rtfrtb.SelectedRtf,还有“纯文本” ExtendedText/rtb.ExtendedText,并且,如果宿主应用程序的目标平台低于 .NET 4.7,则是 rtb.Textrtb.SelectedText。这会影响查找/替换拼写检查等功能会找到并尝试编辑的内容。任何完全或部分受保护的文本(无论是作为自定义链接还是出于其他目的(由宿主程序酌情决定))都不会被修改,除非是链接,并且在替换对话框中选择了忽略它们(参见第 17 点)。
  14. 当处于自定义链接模式时,编辑器允许用户使用插入/编辑/移除工具栏按钮或上下文菜单项(Ctrl + K)创建新链接(从头开始或选定文本),或修改/删除现有链接。用户也可以通过在链接(及其前导隐藏连字符)的左侧或右侧按下 Backspace 或 Delete 键来移除自定义链接。上下文菜单还允许用户设置在移除链接时是否保留超文本在文档中,以及移除选定文本(或全部文本,Ctrl + Shift + F9)中的所有链接。
  15. 上下文菜单还支持删除线字体样式和(通过字符偏移)上标/下标。(如果您想使用“真实”上标/下标,请使用 RichTextBox.vb 中的 Win32 驱动的 IsSelectionStyleInEffectSetSelectionStyle 过程,添加必要的常量以方便这些函数。)
  16. EditingWithLinksUnprotected 事件中 ParameterEventArgsParameters 属性的更改现在会传回 EditWithLinksUnprotected 方法和宿主程序,即使在事件过程中发生未处理的异常!!!
  17. 我*修复了一个错误*,该错误导致在文本框内部或文本框之间发生自定义链接和自动拖放时有时会发生无法恢复的错误。该修复程序在鼠标按钮按下且未按下任何键(可能除了像 [Ctrl] 这样的修饰键)时禁用任何自定义链接保护,然后在释放鼠标按钮、按下非修饰键或底层文本框的 rtb_DragDrop 事件发生时重新启用它。
  18. 当按下非修饰键文本被高亮显示时,自定义链接保护暂时关闭;这允许粘贴和键入覆盖带有自定义链接的高亮文本,但不允许覆盖未高亮链接。
  19. 我进行了一些最后的补充,以确保在查找/替换文本、断字/取消断字以及插入/删除/修改链接时,都已启用自定义链接保护。此外,自定义字符按键现在可用于插入链接对话框中的文本,以及查找/替换对话框和主富文本框。
  20. 当允许自定义链接时,最终用户可以在使用查找/替换时选择跳过链接进行替换,或覆盖与搜索文本出现重叠的链接。任何被覆盖的链接(包括不匹配搜索文本的文本)都会被完整覆盖——因为控件将自定义链接视为“整体”项。注意:如果搜索文本的可见出现“跨越”了链接(而不是完全包含在其中或完全在外面),除非在搜索中指定了分隔链接与非链接文本的“隐藏文本”,否则它将不会被找到,更不用说被替换了。
  21. 我*现在使用 i00 拼写检查器*。此处 ZIP 文件中提供的版本与我从 i00 文章下载的版本略有修改——在拼写检查对话框中的“全部更改”选项方面修复了一个小错误,并提供了禁止自动添加“标准”上下文菜单的功能(对于像我这样使用非标准上下文菜单的项目很有用);此外,对拼写检查进行了修改,使其不会因隐藏的(音节)连字符而无法识别断字词。如果您已经拥有 i00Spell-Checker,请对 i00SpellCheck 项目进行以下更改,我在我的以及 “文本更改和推荐更改的一些问题”帖子(作者:Robert Gustafson)中推荐的更改(注意:有几处,但它们相当直接。帖子中的第一点不是对工具本身的更改,但了解它很有用。其他几点——编号 1 到 8——是更改。)
  22. 由于当启用自定义链接时,控件确保任何选定文本*完整包含*跨越选区边界的链接,因此当没有进行非链接修改自上次插入/更新链接以来,或者选区退回到链接开头时,用户有时无法使用 Shift + [左箭头] 向扩展选区。但是,使用任何其他按键序列向后扩展选区,或使用任何按键序列向前扩展选区,总会成功。

关于自定义链接

默认情况下,RichTextBoxEx 像标准 RichTextBox 一样处理链接,在用户输入 URL 时检测链接。您现在可以禁用此功能,转而使用自定义链接,其中链接具有可见文本和不可见超链接目标文本(鼠标悬停在链接可见文本上时会显示工具提示),用户(使用工具栏或上下文菜单)或以编程方式创建/修改/删除。但是,使用隐藏文本时有很多注意事项。如果用户任意编辑(随意编辑),编辑器可能会表现异常,控件可能会丢失对链接的跟踪或在单击链接时无法正确处理它。(我必须在文档本身中包含不可见超链接,以确保它们能够正确复制粘贴,并能与可见文本一起持久化到文件或数据库。)

为了解决这些问题,我将其设置为如下:自定义链接的语法为“{可见文本|超链接文本}”,其中“可见文本”以外的所有内容都被标记为隐藏文本。此外,编辑器确保每个链接前面和后面都有音节连字符(未标记为“不可见”,但除非链接导致链接中断,否则不会显示),连字符和中间链接是受保护的,以控制用户编辑链接的方式。连字符确保链接*绝不会*出现在段落的开头或彼此紧邻——这些情况会阻止控件在编辑文本时正确跟踪链接(其内容和位置)。

链接使用 SortedList 进行跟踪,其键是链接的起始位置,其值是 CustomLinkInfo 实例,包含位置、(可见)文本和(不可见)超链接信息。每次更改文本时都会重新构建列表;任何出现语法“{可见文本|超链接文本}”并包含隐藏文本的都被视为自定义链接。(这些文本以及任何已标记为链接的文本都会受到保护——包括前后连字符,控件会确保它们存在。)

此外,任何时候高亮显示文本,控件都会扩展选区边界,以确保选区的开头或结尾都不会跨越链接(及其前导连字符)。这可确保剪切/复制/粘贴操作不会创建/破坏不完整且因此不可靠的链接。此外,当文本高亮显示但插入点位于链接的不可见文本上方时,插入点会移到链接之后,以免用户在插入点似乎不在链接上方时收到受保护文本警告。

自定义链接就像正则表达式一样,解释起来很复杂,但实际使用起来却相对简单。

关于此事的最后一点:用于在此处实现自定义链接的 RTF 显然与 Word 或 WordPad 使用的 RTF 非常不同。问题是,Word 用于处理链接的 RTF 在 Visual Studio RichTextBox 中看起来或行为都不相似。讽刺的是,我必须使用*不同的* RTF 代码才能使我的链接看起来和行为像 WordPad/Word 链接!因此,从这个控件复制到 WordPad/Word 的链接可能不被识别为链接,这并不奇怪。这实际上也不是什么大问题,因为即使是标准的“DetectUrls”非自定义链接在 Word 中也不被视为链接(但在 WordPad 中是)。我想每个富文本编辑器都有自己处理链接的方式。

另一个最后的说明:标准的“DetectUrls”键入链接和自定义链接是*互斥的*!您不能同时执行这两种类型。(DoCustomLinks 属性决定了哪种样式可用。)

附注

  1. 自定义链接以前需要一个(可见的)空格而不是连字符来跟在链接前面并与其一起保护。如果您拥有使用此控件在其先前版本中保存的 RTF 文件,我建议在记事本中打开每个 RTF 文件,找到任何不紧跟“0”的“\protect”标签,并编辑其后的文本:在代表链接的每个受保护文本的情况下,将第一个“\v”标签(不是“\v0”标签!)之前的空格(“ ”或“\ ”)替换为“\-”(音节连字符),并且,如果您仍然想在链接前显示空格,请在开始“受保护链接”区域的“\protect”标签(不是结束该区域的“\protect0”标签)之前插入一个空格。(另外,在区域的第二个“\v0”[在“\protect0”之前]之后立即添加一个尾随“\-”,如果*还没有*的话。)
  2. 如果您在处理从旧文件中加载的 RTF 文本并尝试更改跨越链接和非链接文本的选择时遇到保护错误,则可能在链接的“分隔”连字符之前或之后,但在受保护区域内,有多余的隐藏(音节)连字符。在记事本中打开 RTF 文件,并删除“受保护链接”区域(“\protect”和“\protect0”之间的区域)中的任何多余“\-”转义符,以便每个这样的区域内只有 2 个“\-”转义符——1 个在开头,1 个在结尾。
  3. 顺便说一下,您会注意到链接过程——以及 RichTextBoxEx.vb 中的许多其他过程——使用特殊的布尔值来有条件地绕过事件触发的代码。这是有意识地做的,以防止*事件级联*。有许多组件控件相互交互,并且文本和选区更改事件会直接或间接更改文本/选区——因此代码在处理事件时需要知道它是否已经在处理了。其他布尔值可防止无限双递归的情况——即过程可以无限地相互调用。
  4. 我修复了i00SpellCheck 库中的一个错误,该错误会导致宿主应用程序在选择多个单词、使用工具栏组合框更改字体名称或大小,然后单击富文本框时崩溃。如果您有 i00SpellCheck 的*源代码*,请查看我对 i00SpellCheck 文章的评论 “文本更改和推荐更改的一些问题”帖子(作者:Robert Gustafson),以获取拼写检查器解决方案。
© . All rights reserved.