TX Spell .NET for WPF

Incorrect Words and Suggestions

Topic

Behind every red underline and every entry of the spell check context menu are two lists: the words the spell checker found incorrect, and the suggestions it created for one of them. Your code can read both, to build a correction interface of its own, to report the mistakes in a text, or to replace a word with its best suggestion. What follows covers where the lists come from, what each entry holds, and how TX Text Control keeps its own list of misspelled words.

How the Two Lists Are Filled

A TXSpellChecker fills its lists on request, and each request replaces what the previous one found:

You callIt fillsWith
CheckIncorrectWordsAn IncorrectWordCollection: every incorrect word of the text you passed
CreateSuggestionsSuggestionsA SuggestionCollection: the suggestions for one word, closest match first

Both use the dictionaries in Dictionaries. Check must not be called while the spell check dialog is open; it throws an exception.

A TextControl of TX Text Control that is connected to the spell checker does not use these two lists for its underlines. It keeps its own collection of misspelled words, described below.

Find the Incorrect Words of a Text

This button handler checks the text of a TextBox and lists each incorrect word with its position in a ListBox. The window declares a TXSpellChecker with the key txSpellChecker1 in its resources, and the code-behind gets it with FindResource, as As-You-Type Checking shows:

private void buttonCheck_Click(object sender, RoutedEventArgs e)
{
    txSpellChecker1.Check(textBox1.Text);

    listBoxWords.Items.Clear();

    foreach (TXTextControl.Proofing.IncorrectWord incorrectWord in txSpellChecker1.IncorrectWords)
    {
        listBoxWords.Items.Add($"{incorrectWord.Text} at {incorrectWord.Start}, {incorrectWord.Length} characters");
    }

    textBlockCount.Text = $"{txSpellChecker1.IncorrectWords.Count} incorrect word(s)";
}

The code works as follows:

  • Check(textBox1.Text) checks the text against the dictionaries. An overload, Check(string, CultureInfo), also uses the dictionaries of the default dictionary folder that match the language you pass.
  • Each entry is an IncorrectWord. Its Text, Start and Length say which word it is and where. Start counts from 0, so textBox1.Select(incorrectWord.Start, incorrectWord.Length) selects the word.
  • IncorrectWords.Count is the number of incorrect words; 0 means the text is correct.

An IncorrectWord has two more properties:

  • IsDuplicate is true when the word is spelled correctly but repeats the word in front of it, as in "the the".
  • Language is the language the word was checked in, or null when no specific language was set.

The Check simple text sample of the setup uses the count to tell the user whether a text box holds mistakes:

A window with a text box containing "House", a Check spelling button and a message box that says "Spelling is correct."

Create Suggestions for a Word

CreateSuggestions takes one word and fills Suggestions. With a maximum, it stops after that many suggestions; without one, it creates all it can find:

private void listBoxWords_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (listBoxWords.SelectedIndex < 0) return;

    TXTextControl.Proofing.IncorrectWord incorrectWord = txSpellChecker1.IncorrectWords[listBoxWords.SelectedIndex];

    // The five closest matches for the selected word
    txSpellChecker1.CreateSuggestions(incorrectWord.Text, 5);

    listBoxSuggestions.Items.Clear();

    foreach (TXTextControl.Proofing.Suggestion suggestion in txSpellChecker1.Suggestions)
    {
        listBoxSuggestions.Items.Add(suggestion.Text);
    }
}

The code works as follows:

  • The indexer of IncorrectWords counts from 0, like the list box, so the selected line and the word match.
  • CreateSuggestions(incorrectWord.Text, 5) creates the five best suggestions. The collection is sorted by closeness, so Suggestions[0] is the best one.
  • Each Suggestion has one property, Text.

CreateSuggestions has four overloads:

OverloadSuggestions from
CreateSuggestions(string incorrectWord)The selected dictionaries, all suggestions
CreateSuggestions(string incorrectWord, int max)The selected dictionaries, at most max suggestions
CreateSuggestions(string incorrectWord, CultureInfo language)The selected dictionaries and those of the default dictionary folder in language
CreateSuggestions(string incorrectWord, int max, CultureInfo language)The same, at most max suggestions

The suggestions take the keyboard into account, so a key next to the intended one counts as a likely typo. Since version 10.0, they also use the replacement rules, the REP flag, of a Hunspell dictionary, which map common misspellings, such as a missing accent or "f" for "ph", to the correct spelling; Version 10.0 describes the change.

Choose Which Dictionaries Check and Suggest

Check uses only the dictionaries whose IsSpellCheckingEnabled property is true, and CreateSuggestions only those whose IsGetSuggestionsEnabled property is true; both are true by default. A dictionary of technical terms can therefore accept words without filling the suggestions with them, as Switch Off or Remove a Dictionary shows.

Work With the Misspelled Words of TX Text Control

A TextControl with a connected spell checker keeps the words it underlines in MisspelledWords, a MisspelledWordCollection of the text part that has the input focus: the main text, a header or footer, or a text frame. Its entries are MisspelledWord objects, which differ from an IncorrectWord in a few ways:

IncorrectWordMisspelledWord
Belongs toTX Spell .NET, after CheckTX Text Control, kept up to date as the user types
First characterStart counts from 0Start counts from 1
Collection indexFrom 0From 1
Can be marked as ignoredNo, it has no such propertyYes, IsIgnored keeps it without the underline

To correct a word in the editor, get it from the collection, create suggestions for its text, and pass the replacement to Remove. This handler replaces the misspelled word at the input position with its best suggestion:

private void buttonCorrect_Click(object sender, RoutedEventArgs e)
{
    // The misspelled word at the input position, or the next one
    TXTextControl.MisspelledWord misspelledWord = textControl1.MisspelledWords.GetItem();
    if (misspelledWord == null) return;

    txSpellChecker1.CreateSuggestions(misspelledWord.Text, 1);

    if (txSpellChecker1.Suggestions.Count > 0)
    {
        // Replace the text of the word with the suggestion
        textControl1.MisspelledWords.Remove(misspelledWord, txSpellChecker1.Suggestions[0].Text);
    }
}

The code works as follows:

  • GetItem without arguments returns the misspelled word at the input position. If there is none, it returns the next one, and after the last word it starts again at the first. Other overloads take a text position or a kind of misspelled word.
  • Remove(misspelledWord, text) replaces the word's text with the suggestion. Remove(misspelledWord) without a text only drops the word from the collection and leaves the text as it is.

The spell check context menu offers the same kind of correction for the word the user right-clicked:

A context menu over the misspelled word "sampke" with the suggestions sample, spake, smoke, samples and sampler.

The same calls can correct words automatically while the user types. The blog article AutoCorrect Using TX Text Control and TX Spell .NET does this in a Windows Forms application: when the user types a delimiter such as a space or a period right after a misspelled word, it creates one suggestion and replaces the word with it through MisspelledWords.Remove. A word the user changes back is left alone the second time.

Check Text Without a User Interface

The TXSpell class has the same Check, IncorrectWords, CreateSuggestions and Suggestions members, without the dialogs, the context menus and the events, and must be initialized with Create first. It suits code that only checks text, such as the validation rule of As-You-Type Checking. Checking Text in Code introduces it step by step.

Next Steps