So our back-end application at work runs on Windows Forms. Windows Presentation Foundation looks cool, and I’ll certainly want to learn it some day, but it didn’t exist at the time that our back-end application was started, it’s hard for a developer without a good sense of the aesthetic to build a decent interface, it pretty much requires Visual Studio 2008 (which I don’t have the luxury of purchasing at this time), and it flies in the face of over a decade of user32 programming. So we’ll be stuck with Windows Forms for a while.
Why do I bring WPF up? Well, the default text controls in WPF have “wavy red line spell checking” built right in, which is awesome. But there’s no joy for the Windows Forms world. There are lots of components out there for this, but they’re either expensive or bundled together with much larger control suites that I don’t need. (By expensive, I generally mean anything over fifty bucks.)
Being used to being able to Google just about anything and find an open source version somewhere, I was pretty surprised that I haven’t been able to track down a free version of a spell checker. I found plenty of free spell checking engines (one of which I used in my implementation) as well as snippets from people who have written wavy red line algorithms for MFC-based controls, but there was no love for Windows Forms. I was, however, able to cobble together a solution from these snippets and piece together something that works. It’s not very heavyweight or robust, but it’s great in small text boxes, such as the product description field in our application.

This is my implementation. You attach a provider to a text box and you'll get wavy red lines underneath misspelled words. Right-click the word and you'll see a pop up menu with some spelling suggestions.
An Overview of What We’re Building
To make this as painless to use as possible, I built the spell checker as an IExtenderProvider. If you’ve used things like Tooltip or ErrorProvider in Windows Forms before, it works the same way: you drag and drop a SpellChecker onto your form in the Visual Studio visual designer. Then, any control on that form that inherits from TextBoxBase magically gets a SpellCheckEnabled on mSpellChecker property. Set that to true and the visual designer adds some magic in the designer file that registers the textbox with the spellchecker, enabling it to get the wavy red line spellchecking behavior that I’ve programmed.

So you drag the (1) SpellChecker onto the form. Here I've named it mSpellChecker. Then when you click on a (2) TextBox control, it gets a new (3) SpellCheckEnabled property. That's it!
A Spell Checking Interface
When I first used the control, I piggybacked onto Microsoft Word to do the spellchecking for me. It worked well for the spike, but I quickly discovered that it was a pain to have to ensure that every client has the right version of Word installed on their computer. So I switched the engine implementation over to NetSpell, a free and open source spell checking engine. In the process, however, I abstracted out the spell checking engine that my new SpellChecker uses and made it pluggable.

Similarly, you just drag a spell checking engine provider onto the form and hook it up to the SpellChecker component.
So, without any further ado, here’s the interface that these spell checking engine providers need to adhere to:
/// <summary>
/// For a service to provide spell checking capabilities to the SpellChecker
/// extender provider, it needs to implement this interface.
/// </summary>
public interface ISpellCheckerProvider : IDisposable
{
#region Methods
/// <summary>
/// Adds a user-defined word to the dictionary.
/// </summary>
/// <param name="word">the word</param>
void AddWord(string word);
/// <summary>
/// Tests to see if the given word is in the dictionary
/// (that is, not misspelled).
/// </summary>
/// <param name="word">the word to test</param>
/// <returns>whether or not the word is in the dictionary</returns>
bool IsWordInDictionary(string word);
/// <summary>
/// Returns an array of suggested spellings for the given misspelled
/// word.
/// </summary>
/// <param name="word">the word</param>
/// <returns>the suggested spellings</returns>
string[] SuggestSpellings(string word);
#endregion
#region Properties
/// <summary>
/// Gets whether or not the object has been disposed.
/// </summary>
bool IsDisposed
{
get;
}
/// <summary>
/// Gets whether or not the provider supports adding user-defined
/// words to its dictionary.
/// </summary>
bool SupportsAddingWords
{
get;
}
#endregion
}
As you can see, it’s a pretty simple interface: you can add words to your local dictionary (which not all implementors may support), you can test to see if a word is misspelled, and you can suggest some alternative spellings for a misspelled word.
Here’s how the implementation that uses NetSpell looks:
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using NetSpell.SpellChecker;
using NetSpell.SpellChecker.Dictionary;
public class NetSpellSpellCheckerProvider : Component, ISpellCheckerProvider
{
#region Members
private Spelling mSpelling;
private readonly object mSpellingLock = new object();
#endregion
#region Constructors
public NetSpellSpellCheckerProvider()
{
mSpelling = new Spelling();
mSpelling.Dictionary = new WordDictionary();
mSpelling.Dictionary.EnableUserFile = true;
}
public NetSpellSpellCheckerProvider(IContainer container) : this()
{
container.Add(this);
}
#endregion
#region Public Methods
public void AddWord(string word)
{
lock (mSpellingLock)
{
if (SupportsAddingWords)
{
mSpelling.Dictionary.Add(word);
}
}
}
public bool IsWordInDictionary(string word)
{
bool isInDictionary;
lock (mSpellingLock)
{
isInDictionary = mSpelling.TestWord(word);
}
return isInDictionary;
}
public string[] SuggestSpellings(string word)
{
string[] suggestions;
lock (mSpellingLock)
{
mSpelling.Suggest(word);
suggestions = new string[mSpelling.Suggestions.Count];
mSpelling.Suggestions.CopyTo(suggestions);
}
return suggestions;
}
#endregion
#region Properties
public string DictionaryFileName
{
get { return mSpelling.Dictionary.DictionaryFile; }
set { mSpelling.Dictionary.DictionaryFile = value; }
}
public bool IsDisposed
{
get { return false; }
}
public bool SupportsAddingWords
{
get { return mSpelling.Dictionary.UserFile != null; }
}
#endregion
}
How simple is that? The only thing that makes it slightly complicated is being sure to do a lock whenever we’re dealing with the spelling dictionary. It turns out that NetSpell isn’t happy if, say, one thread is adding a word to the dictionary while another thread is trying to read one. Not too difficult to work around, however.
Implementing the IExtenderProvider
So now let’s write the bit of code that lets the Visual Studio visual designer add those magic SpellCheckEnabled properties to our textboxes.
Let’s start at the beginning:
/// <summary>
/// An extender provider that will provide as-you-type spell checking (with
/// wavy red underlines) to a control that inherits from TextBoxBase.
/// </summary>
[ProvideProperty("SpellCheckEnabled", typeof(TextBoxBase))]
public class SpellChecker : Component, IExtenderProvider, ISupportInitialize
{
// TODO
}
The ProvideProperty attribute is what tells Visual Studio to add a SpellCheckEnabled property to controls that inherit from TextBoxBase. When we change the default property value on one of those controls, Visual Studio will call GetSpellCheckEnabled() and SetSpellCheckEnabled() methods. (It does this by well-known name mangling. If I had called it DeathDefyingStuntsEnabled, then Visual Studio would be calling methods named GetDeathDefyingStuntsEnabled() and SetDeathDefyingStuntsEnabled().) So let’s add those to our new class:
/// <summary>
/// A mapping of the TextBoxBase controls that are being extended to a
/// class that contains various information about the control.
/// </summary>
private Dictionary<textBoxBase, SpellCheckInfo> mControls;
/// <summary>
/// Gets whether or not spell checking is enabled for the given control.
/// </summary>
/// <param name="control">the control to test</param>
/// <returns>whether or not spell checking is enabled for the control</returns>
public bool GetSpellCheckEnabled(TextBoxBase control)
{
return control != null && mControls.ContainsKey(control);
}
/// <summary>
/// Sets whether or not spell checking is enabled for the given control.
/// </summary>
/// <param name="control">the control to enable or disable</param>
/// <param name="enabled">the enabled status</param>
public void SetSpellCheckEnabled(TextBoxBase control, bool enabled)
{
if (control == null)
{
throw new ArgumentNullException("control");
}
if (enabled)
{
mControls.Add(control, new SpellCheckInfo());
}
else
{
mControls.Remove(control);
}
}
What I’m doing is having the SpellChecker instance store a dictionary that maps the TextBoxBases that are added by a call to SetSpellCheckEnabled to their corresponding SpellCheckInfo objects. The SpellCheckInfo object is just a quick and dirty class (it could have been a structure, really) that’s used when drawing the wavy red lines underneath the control. I’ll get to how that’s used later, but essentially all you need to know is that it holds the list of misspelled words in the textbox.
Drawing the wavy red lines
So how do we alter the behavior of these textboxes to draw wavy red lines underneath the misspelled words? We obviously can’t just inherit from TextBox. Otherwise, you’d have to drag and drop a new control on your form instead of a regular TextBox, and that would defeat the whole purpose of having the extender provider.
The secret is to use NativeWindow to listen to the messages that get pumped to each registered TextBox. Whenever they repaint themselves, we’ll paint on top of them the wavy red lines that are necessary. The textboxes won’t even know what hit them!
Our extension of NativeWindow, which I’ve called SpellCheckingTextBox, takes a TextBoxBase and our own SpellCheckInfo object in its constructor and attaches itself so that its WndProc method will see all of the messages that are getting pumped to that TextBoxBase. Here’s what our WndProc looks like:
/// <summary>
/// Processes Windows messages.
/// </summary>
/// <param name="m">the message to process</param>
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case (int)WindowsMessages.WM_PAINT:
mControl.Invalidate();
base.WndProc(ref m);
Repaint();
break;
case (int)WindowsMessages.WM_CONTEXTMENU:
Point pt;
pt = GetPointFromLParam(m.LParam);
pt = mControl.PointToClient(pt);
if (!DisplaySpellingSuggestionsMenu(pt))
{
base.WndProc(ref m);
}
break;
default:
base.WndProc(ref m);
break;
}
}
There’s nothing too exotic going on here. When the TextBoxBase is told by Windows to paint itself, we go ahead and let it do that. But then we call our own Repaint() method.
Similarly, if Windows is asking the TextBoxBase control to draw a popup menu (usually because the user right-clicked their mouse), then we intercept that little message and decide if we want to pop up our own menu of spelling suggestions. If we do, we show it at the correct position on screen with our own DisplaySpellingSuggestionsMenu() method and swallow the message. Otherwise, we pass the message onto the TextBoxBase itself by calling base.WndProc().
The Repaint() method is where the fun happens:
/// <summary>
/// Draws the red wavy lines under misspelled words.
/// </summary>
private void Repaint()
{
Graphics g;
g = Graphics.FromHwnd(mControl.Handle);
g.Clip = new Region(mControl.ClientRectangle);
lock (mMisspelledWords)
{
foreach (Match word in mMisspelledWords)
{
int endIndex;
Point start;
Point stop;
endIndex = word.Index + word.Length;
start = mControl.GetPositionFromCharIndex(word.Index);
// For some reason, GetPositionFromCharIndex() freaks out if called
// on the last character in the textbox (that is, the misspelled word
// is also the last word). We have to do one character prior and figure
// out how long the line should be.
if (endIndex == mControl.TextLength)
{
Size charSize;
charSize = TextRenderer.MeasureText(word.Value.Substring(word.Length - 1), mControl.Font);
stop = mControl.GetPositionFromCharIndex(endIndex - 1);
stop.Offset(charSize.Width, 0);
}
else
{
stop = mControl.GetPositionFromCharIndex(endIndex);
}
start.Offset(0, mControl.Font.Height);
stop.Offset(0, mControl.Font.Height);
DrawWavyLine(g, start, stop);
}
}
g.Dispose();
}
There’s nothing too hard going on here since the TextBoxBase provides some great methods for determining the pixel positions of words that are contained within it. On a paint event, we just loop through our SpellCheckInfo object (called mMisspelledWords here). For each of those words, we measure the size of the word in the text box and then we call DrawWavyLine at those points, a neat method that I totally lifted from some guy’s blog:
/// <summary>
/// Draws a red wavy line at the given start and stop points with the given
/// graphics context. Got to give credit where it's due -- this function (and
/// pretty much the inspiration for this entire class) is lifted straight
/// from the great work of Andrei Alecu at
/// http://www.codedblog.com/2007/09/17/owner-drawing-a-windowsforms-textbox/.
/// </summary>
/// <param name="g">the graphics context</param>
/// <param name="start">the start point</param>
/// <param name="stop">the stop point</param>
private void DrawWavyLine(Graphics g, Point start, Point stop)
{
Pen pen;
pen = Pens.Red;
if ((stop.X - start.X) > 4)
{
List<point> points;
points = new List<point>();
for (int i = start.X; i <= (stop.X - 2); i += 4)
{
points.Add(new Point(i, start.Y));
points.Add(new Point(i + 2, start.Y + 2));
}
g.DrawLines(pen, points.ToArray());
}
else
{
// If the line is really short, don't bother with
// any waves
g.DrawLine(pen, start, stop);
}
}
That’s pretty much the meat of the NativeWindow implementation–it’s concerned about the display and painting of the information in the SpellCheckInfo object. The actual behind-the-scenes spellchecking is performed by a background thread that’s maintained by the SpellChecker extender provider:
/// <summary>
/// Performs the spell checking on the control.
/// </summary>
/// <param name="control">the control</param>
private void PerformAsYouTypeSpellChecking(TextBoxBase control)
{
SpellCheckInfo info;
List<match> misspelledWords;
string controlText;
MatchCollection words;
if (control == null)
{
throw new ArgumentNullException("control");
}
if (control.InvokeRequired)
{
IAsyncResult result = control.BeginInvoke((ReturnControlTextDelegate)delegate()
{
return control.Text;
});
controlText = (string)control.EndInvoke(result);
}
else
{
controlText = control.Text;
}
if (mControls.TryGetValue(control, out info))
{
misspelledWords = new List<match>();
words = mReWords.Matches(controlText);
foreach (Match word in words)
{
string text;
text = word.Captures[0].Value;
try
{
if (!mSpellCheckerProvider.IsWordInDictionary(text))
{
misspelledWords.Add(word);
}
}
catch (ApplicationException)
{
// If the spell checking provider went down, let's not
// bother checking it any more this session
break;
}
if (mIsRefreshPending)
{
break;
}
}
// If the text has changed during the time it took us to process this
// request, let's just forget everything and try again
if (mIsRefreshPending)
{
mIsRefreshPending = false;
PerformAsYouTypeSpellChecking(control);
}
else
{
lock (info.MisspelledWords)
{
info.MisspelledWords.Clear();
info.MisspelledWords.AddRange(misspelledWords);
}
control.Invalidate();
}
}
}
Is it the cleanest code? Probably not–there’s some issues with disposing that are kind of nasty. And there are some optimizations that could be made: for example, the wavy red lines disappear while you’re typing. And it probably breaks down for very long passages of text since it basically rescans the entire textbox every time the text changes. But in general, it works pretty well, especially for an in-house app. Download it and see how well it works for you!

The sample application shows how to use the code that I've presented here.
Spell Check Sample Application
If you have any suggestions for improvement, drop me a line. Good luck!