About Spellchecker

Netspell

The NetSpell project is a spell checking engine written entirely in managed C# .NET code. NetSpell's suggestions for a misspelled word are generated using phonetic (sounds like) matching and ranked by a typographical (looks like) score. NetSpell supports multiple languages and the dictionaries are based on the OpenOffice Affix compression format. The library can be used in Windows or Web Form projects. The download includes an English dictionary with dictionaries for other languages available for download on the project web site. NetSpell also supports user added words and automatic creation of user dictionaries. It also includes a dictionary build tool to build custom dictionaries.

The Dictionary

The root of all spell checkers is a word list, aka the dictionary. The dictionary contains a list of common words for a language. For example, the US English dictionary that comes with this package contains 162,573 words. When designing the dictionary for NetSpell I wanted the dictionary to be a single file, be as small as possible and load extremely fast. I experimented with many different ways to save and load the large word lists. Techniques I tried ranged from a saved dataset to a binary serialized collection, all of which proved to be too slow. I ended up using the good old UTF8 text file. Loading and parsing a text file proved to be extremely fast.

Exercise

To check the module out go these steps:

Alternatively you can check using a non-modal dialog. To do so, cancel background spellchecking first. Then, hit "Start Dialog".

Basic Features

The spellchecker is made as a plug-in. That means, you can remove the assembly from your project if you don't need this. You can even remove all dictionary not in use.

The features at a glance:

Code

The spellchecker has two modes: Background (aka "As you type") and Dialog. The background mode checks the documents completely for the first time and looks for specific events after, such as key strokes and mouse moves. If the caret is moved away from a word the checker looks up just this one word in the dictionary. That way the spellchecker is able to check huge documents without noticible delay.
Before you can start the spellchecker, you have to set a dictionary. There are severel dictionaries available. The following code snippet shows the procedure:
object item;
_dropdownSpellerDictionary.ItemsSource.GetItem(_dropdownSpellerDictionary.SelectedItem, out item);
// assume we keep the default path
EditorDocument.SpellChecker.GetSpeller(EditorDocument.HtmlEditor).DictionaryPath = "Dictionary";
// and get the dictionary name from drop down
EditorDocument.SpellChecker.GetSpeller(EditorDocument.HtmlEditor).Dictionary = String.Format("{0}.dic", ((GalleryItemPropertySet)item).Label);
// stop current checking, remove all segments and restart immediately
EditorDocument.HtmlEditor.InvokeCommand(EditorDocument.SpellChecker.Commands.StopBackground);
EditorDocument.HtmlEditor.InvokeCommand(EditorDocument.SpellChecker.Commands.RemoveHighLight);
EditorDocument.HtmlEditor.InvokeCommand(EditorDocument.SpellChecker.Commands.ClearBuffer);
EditorDocument.HtmlEditor.InvokeCommand(EditorDocument.SpellChecker.Commands.StartBackground);
The Label returned from ribbon contains a simple culture string, such as "en-US" or "de-DE". After the dictionary has been set, the background spellchecker is activated.

The commands supported by this plug-in are exposed in the Commands property. Use InvokeCommand to activate the command.

Several settings are available. All settings can be reached through the property bag. The ribbon commands in the demo application invoke these properties like this:
void _comboboxSpellerHighlightUnderlineStyle_ExecuteEvent(object sender, ExecuteEventArgs e)
{
    GuruComponents.Netrix.WebEditing.HighLighting.UnderlineStyle style = (GuruComponents.Netrix.WebEditing.HighLighting.UnderlineStyle)Enum.Parse(typeof(GuruComponents.Netrix.WebEditing.HighLighting.UnderlineStyle), _comboboxSpellerHighlightUnderlineStyle.StringValue);
    EditorDocument.SpellChecker.GetSpellChecker(EditorDocument.HtmlEditor).HighLightStyle.UnderlineStyle = style;
}
 
void _colorpickerSpellerHighlightColor_ExecuteEvent(object sender, ExecuteEventArgs e)
{
    EditorDocument.SpellChecker.GetSpellChecker(EditorDocument.HtmlEditor).HighLightStyle.LineColor.ColorValue = _colorpickerSpellerHighlightColor.Color;
}
One typical scenario is the usage of a context menu with suggestions. The following event handler creates a context menu with some static items and adds a list of suggestions:
void speller1_WordOnContext(object sender, GuruComponents.Netrix.SpellChecker.WordOnContextEventArgs e)
{
    contextMenuTabPage.Items.Clear();
    // Add Spellchecker suggestions
    if (speller1.GetSpellChecker(htmlEditor1).BackgroundService)
    {
        speller1.GetSpellChecker(htmlEditor1).Suggest(e.Word);
        List<string> suggestions = speller1.GetSpellChecker(htmlEditor1).Suggestions;
        if (suggestions != null && suggestions.Count > 0)
        {
            foreach (string suggestion in suggestions)
            {
                contextMenuTabPage.Items.Add(suggestion, null, (o, ea) => speller1.GetSpellChecker(htmlEditor1).ReplaceWord(suggestion));
            }
        }
        else
        {
            ToolStripItem noSuggestion = contextMenuTabPage.Items.Add("No Suggestions");
            noSuggestion.Enabled = false;
        }
    } 
    // Show add desired position (Plug-in delivers the suggested position)
    contextMenuTabPage.Show(e.Position);
}
You have to call the method Suggest first. You can retrieve all suggestions through the Suggestions property, then. The explicit call is necessary to avoid the creation of suggestions all the time, because it is time consuming.

Note: It's necessary to use the speller's context menu call, because the regular context menu event appears to early and the speller has not yet pulled out the current word. This is the reason why the speller has its own context menu event.

Dialog Spell Checker

The dialog spellchecker is implemented as a number of events. There is no dialog integrated. You can use the dialog from demo application as a suggestion. The following code shows how the dialog interacts with the events:
// Dialog for word by word checking
private Spellchecker SpellCheckerDialog;
 
// Get an instance once required
private Spellchecker GetSpellCheckerDialog()
{
    if (SpellCheckerDialog == null)
    {
        SpellCheckerDialog = new Spellchecker();
        SpellCheckerDialog.TopMost = true;
        SpellCheckerDialog.FormClosed += new FormClosedEventHandler(SpellCheckerDialog_FormClosed);
        SpellCheckerDialog.Show(this);
    }
    return SpellCheckerDialog;
}
 
void SpellCheckerDialog_FormClosed(object sender, FormClosedEventArgs e)
{
    SpellCheckerDialog = null;
}
 
void speller1_DoubledWord(object sender, GuruComponents.Netrix.SpellChecker.NetSpell.SpellingEventArgs e)
{
    GetSpellCheckerDialog().WrongWord = e.Word;
}
 
void speller1_EndOfText(object sender, GuruComponents.Netrix.SpellChecker.NetSpell.SpellingEventArgs e)
{
    MessageBox.Show("Reached end of text.""Spellchecker"MessageBoxButtons.OK);
}
 
void speller1_MisspelledWord(object sender, GuruComponents.Netrix.SpellChecker.NetSpell.SpellingEventArgs e)
{
    GetSpellCheckerDialog().WrongWord = e.Word;
}