Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / DevOps / load-testing

NHunspell Component for Visual Studio

4.90/5 (31 votes)
1 Sep 2013CPOL6 min read 2   4.1K  
NHunspell component example for WindowsForms
Image 1

Contents

Introduction

This article shows how to create reusable and extendible spellchecking component based on NHunspell.

Background

The history began about a year ago when I decided to write an application with spellchecking. I discovered lots of .NET components doing what I want, but all of them except NetSpell were proprietary. I looked through lots of C++ code while investigating how things work in other solutions. But then I understood that work is still in the starting phase and started with NetSpell to get some rough solution.

NetSpell

NetSpell is free spellchecking engine that was developed in 2004 for .NET.

The first goal was to add spellchecking functionality to RichTextBox control. When I realized it, I was very proud of myself. It was working! But then, I needed to add such functionality to MaskedTextBox control. I realized that my implementation was too sticky and I should spend almost the same time for integration to any new control. Implementation of such things should be at least as possible binding to any control or project. It must be self-sufficient. It should be some attachable thing that I can use any time I want it, like a book to check spelling and put it back on shelf.

Then I read some design patterns and began writing my implementation for any control use. I used Singleton for Instance property, and used it from any form to notify spellchecking engine about control it should check spelling. Then of course, I wanted to add some wavy underlining to the text and found WINAPI solution here. When I realized it, I was very proud of myself. My spellchecking engine worked for any text control and also could draw wavy underlines. But then I discovered that WINAPI underlining does not always work properly with different fonts. This was a crash. I desperately didn't want to draw those lines myself. But then another solution came to me from the skies here. It was describing how to draw those underlines overriding WndProc method of control and adding some custom painting functionality.

NHunspell

Hunspell is a wrapper for commonly used Hunspell engine. Hunspell is C++ library that is used in such application as: OpenOffice, Mozilla Firefox/Thunderbird, Opera 10, The Bat! and many others.

After a couple of months, I discovered that there is a .NET wrapper for Hunspell. I looked into my last solution and found that if I want to add spellchecking to other projects, I still will have to copy lots of code with my hands. This was a crash. I understood that such things should be not only not binding a control, but also they should not be bound to the initial solution. The code must be reusable. If you write code with this thought in mind, your code can become more than just one time implementation for the same time. I needed to write a component that is possible to just include in my solution and use. The component should do everything it needs by self means and should expose as many events to satisfy every programmers' needs (I hand some problems using NetSpell because there were no events I desperately needed and I had to rewrite some code in existing library and recompile it).

I understand that some controls should handle underlining and some need not. So I described basic interface ISpellingControl and then extended it with IUnderlineable interface. Now I have IUnderlineableSpellingControl interface for richTextBox like controls and ISpellingControl for all others.

Concepts

NHunspellComponent/SpellingWorker.png

As you can see in the first diagram, NHunspellWrapper lives its own life and exposes Instance property to others. We need only 1 instance per application. We can have as many SpellingWorkers as we need. SpellingWorker class has link to Editor it works with.

Attention: In different libraries, properties can have the same name and even declaration but in runtime, if you try to cast one type to other, property will return null.

For example: DevExpress.XtraEditors.BaseEdit has Text property. In your code, you have written some class that works with TextBoxBase that also has such property. If you try to cast one type to another and use its Text property, it will return a null value. So be careful with this.

The next diagram shows how you can solve this issue.

NHunspellComponent/ISpellingControl.png

As I pointed before, we use Interface injection here. So now our component can work with most classes that have identical definitions through this interface. Anyway if ClassA we want to use doesn't have the needed definitions, we should describe them for component to work with ClassA properly.

Using the Code

To use the SpellingWorker component, you will have to add reference to NHunspellComponent to your project. Also add compatible dictionaries to your project and Hunspellx86/x64.dll and set your project properties post-build action to look like this:

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

Drag the component onto the form and select the appropriate editor (that implements ISpellingControl or IUnderlinableSpellingControl interfaces). That's it.

Spelling Control

Implementing ISpellingControl in general is usually doesn't need much work because all properties and methods are already present in text editor control. So as you can see in the example application, we need to add this interface to CustomMaskedTextBox and implement unique properties of ISpellingControl only (those are IsSpellingEnabled, IsSpellingAutoEnabled, IsPassWordProtected). You can read about interface injection in Inversion of control and Dependency injection articles.

Spelling Window

Image 4

Image 5

Spelling window should notify NHunspellWrapper about the changes it makes. Also it should expose properties that will allow other classes to change its view.

Options are stored in spelling worker for each control. So you can setup individual options.

Wavy Underlines

Image 6

One of the main problems during spell check is notifying the user about the mistake just made. You can use any action you want. You can launch fireworks at each misspelled word on UnderliningChanged event. But I prefer underlining them with red waves. So I describe how it was done in the sample application:

  1. Method WndProc of control that implements IUnderlinable was overridden to call CustomPaint method.
  2. CustomPaint method used to manipulate bitmaps of editor's region. It draws wavy underlines under each item of UnderlinedSections property.
  3. DrawWave method is used to draw a zigzag line from point to point.

Points of Interest

I learned how to write components and the most irritating thing is that you have to do some dancing with tambourine to draw those wavy underlining we are so used to as users. They are not necessary conditions for components to work and are shown in TestApplication project in CustomPaintRichText class. You can see it as an example, but if you need something that really works, it needs to be well tested.

Also I had trouble with displaying SpellingWorker component in Visual Studio toolbox.

The most clever thing about writing any library is to implement it as a reusable library, so you won't need to rewrite your code in future. Design patterns and practices will help you with this and of course solve problems again and again to gain experience. You won't learn anything from just reading articles unless you are a person with extrasensory perception.

History

This is the initial version of the article.

Updated source code

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)