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

适用于 Visual Studio 的 NHunspell 组件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (30投票s)

2010年4月18日

CPOL

6分钟阅读

viewsIcon

125843

downloadIcon

4142

适用于 WindowsForms 的 NHunspell 组件示例

目录

引言

本文介绍了如何基于 NHunspell 创建可重用且可扩展的拼写检查组件。

背景

故事始于大约一年前,当时我决定编写一个带拼写检查功能的应用程序。我发现了许多.NET 组件可以实现我的需求,但除了 NetSpell 之外,它们都是专有的。在研究其他解决方案的工作原理时,我查阅了大量的 C++ 代码。但后来我意识到工作还处于起步阶段,于是从 NetSpell 开始,得到一个大致的解决方案。

NetSpell

NetSpell 是一个免费的拼写检查引擎,于 2004 年为 .NET 开发。

第一个目标是将拼写检查功能添加到 RichTextBox 控件。当我实现它时,我对自己非常自豪。它奏效了!但后来,我需要将此功能添加到 MaskedTextBox 控件。我意识到我的实现太固定了,集成到任何新控件都需要花费几乎相同的时间。此类实现的绑定应尽可能松散,并且应独立于任何控件或项目。它必须是自给自足的。它应该是一个可以随时使用的附加组件,就像一本检查拼写然后放回书架的书一样。

然后我阅读了一些设计模式,开始编写适合任何控件使用的实现。我为 Instance 属性使用了 Singleton,并从任何窗体中使用它来通知拼写检查引擎它应该检查拼写的控件。当然,然后我想在文本上添加一些波浪线,并在此处找到了 WINAPI 解决方案。当我实现它时,我对自己非常自豪。我的拼写检查引擎适用于任何文本控件,还可以绘制波浪线。但随后我发现 WINAPI 下划线在不同的字体下并不总是正常工作。这是一个崩溃。我极不情愿自己绘制这些线条。但然后另一个解决方案从天而降在此。它描述了如何通过覆盖控件的 WndProc 方法并添加一些自定义绘制功能来绘制这些下划线。

NHunspell

Hunspell 是一个常用 Hunspell 引擎的包装器。Hunspell 是一个 C++ 库,用于诸如 OpenOffice、Mozilla Firefox/Thunderbird、Opera 10、The Bat! 等应用程序,以及许多其他应用程序。

几个月后,我发现有一个 Hunspell 的 .NET 包装器。我查看了我之前的解决方案,发现如果我想将拼写检查添加到其他项目,我仍然需要手动复制大量代码。这是一个崩溃。我意识到此类事物不仅不应绑定到控件,而且不应绑定到初始解决方案。代码必须是可重用的。如果您编写代码时能考虑到这一点,您的代码的价值将远不止一次实现。我需要编写一个组件,可以简单地包含在我的解决方案中使用。该组件应自行完成所有工作,并公开尽可能多的事件来满足每个程序员的需求(我在使用 NetSpell 时遇到了一些问题,因为没有我迫切需要的事件,我不得不重写现有库中的一些代码并重新编译它)。

我明白有些控件应该处理下划线,有些则不需要。所以我描述了基本的 ISpellingControl 接口,然后用 IUnderlineable 接口对其进行了扩展。现在我有了 IUnderlineableSpellingControl 接口,用于 richTextBox 等控件,以及用于所有其他控件的 ISpellingControl

概念

NHunspellComponent/SpellingWorker.png

正如您在第一张图中看到的,NHunspellWrapper 独立运行,并向外部公开 Instance 属性。我们每个应用程序只需要一个实例。我们可以拥有任意数量的 SpellingWorkers SpellingWorker 类链接到它正在处理的编辑器。

注意:在不同的库中,属性可以具有相同的名称甚至相同的声明,但在运行时,如果您尝试将一种类型转换为另一种类型,属性将返回 null

例如:DevExpress.XtraEditors.BaseEdit 有一个 Text 属性。在您的代码中,您编写了一个处理 TextBoxBase 的类,该类也有一个这样的属性。如果您尝试将一种类型转换为另一种类型并使用其 Text 属性,它将返回 null 值。所以要小心。

下一张图显示了如何解决此问题。

NHunspellComponent/ISpellingControl.png

正如我之前指出的,我们在这里使用依赖注入。因此,现在我们的组件可以通过此接口处理具有相同定义的类。但是,如果我们要使用的 ClassA 没有必要的定义,我们应该为组件提供这些定义,以便它能正确处理 ClassA

Using the Code

要使用 SpellingWorker 组件,您需要在项目中添加对 NHunspellComponent 的引用。还要添加兼容的字典到您的项目以及Hunspellx86/x64.dll,并设置您项目的属性以使生成后操作如下所示。

xcopy "$(ProjectDir)Dictionaries" "$(TargetDir)" /ICRY
xcopy "$(ProjectDir)Hunspell" "$(TargetDir)" /ICRY 

将组件拖放到窗体上,然后选择适当的编辑器(实现 ISpellingControlIUnderlinableSpellingControl 接口)。就是这样。

拼写控件

实现 ISpellingControl 通常不需要太多工作,因为文本编辑器控件已经存在所有属性和方法。因此,正如您在示例应用程序中看到的,我们需要将此接口添加到 CustomMaskedTextBox 并仅实现 ISpellingControl 的独特属性(例如 IsSpellingEnabledIsSpellingAutoEnabledIsPassWordProtected)。您可以阅读有关接口注入的内容,控制反转依赖注入的文章。

拼写窗口

拼写窗口应通知 NHunspellWrapper 其所做的更改。它还应公开允许其他类更改其视图的属性。

每个控件的选项都存储在拼写工作器中。因此,您可以设置单独的选项。

波浪线

拼写检查过程中的主要问题之一是通知用户刚刚犯的错误。您可以使用任何您想要的动作。您可以在 UnderliningChanged 事件中为每个拼写错误的单词发射烟花。但我更喜欢用红色的波浪线来标记它们。所以我描述了在示例应用程序中是如何完成的。

  1. 实现 IUnderlinable 的控件的 WndProc 方法被重写以调用 CustomPaint 方法。
  2. CustomPaint 方法用于处理编辑器区域的位图。它在 UnderlinedSections 属性的每个项目下绘制波浪线。
  3. DrawWave 方法用于从点到点绘制锯齿线。

关注点

我学会了如何编写组件,最令人恼火的是,您必须做一些繁琐的工作才能绘制我们用户习惯的那些波浪线。它们不是组件工作的必要条件,并且在 TestApplication 项目的 CustomPaintRichText 类中显示。您可以将其视为一个示例,但如果您需要真正起作用的东西,它需要经过充分的测试。

此外,我在将 SpellingWorker 组件显示在 Visual Studio 工具箱中时遇到了麻烦。

编写任何库最聪明的方法是将其实现为一个可重用库,这样您就不需要在未来重写代码。设计模式和实践将有助于您实现这一点,当然,反复解决问题以获得经验。除非您具有超感官知觉,否则您将无法从仅阅读文章中获得任何东西。

历史

这是文章的初稿。

更新了源代码

© . All rights reserved.