TX Spell .NET for WPF

Loading and Managing Dictionaries

Topic

Every check of TX Spell .NET runs against the dictionaries in one collection. Which dictionaries it holds decides what is correct: English only by default, English and German once you add the German dictionary, or a specialist vocabulary on top. Here is where the spell checker finds dictionary files, which one it loads by itself, and how your code adds, switches off and removes dictionaries while the application runs.

Where the Spell Checker Finds Dictionaries

TX Spell .NET looks for dictionary files in its default dictionary folder, a folder named Dictionaries next to the application or, on the development machine, below the Assembly folder of the installation. Both places are what the default of DictionariesDirectoryPath, "(Auto)", stands for; set the property to keep the dictionaries elsewhere. Where the Spell Checker Looks describes the lookup, and Dictionaries Not Found lists the messages when a folder is missing.

Which Dictionary Is Loaded First

The Language property of the spell checker chooses the dictionary it loads by itself, the default dictionary. Its value is "(Auto)" when you declare a TXSpellChecker in XAML:

  1. The spell checker loads the dictionary of the language the application runs in, if the default folder has it.
  2. Otherwise it loads a dictionary of a close language: in a British English environment with only en_US.dic and de_DE_frami.dic in the folder, it takes en_US.dic.
  3. Otherwise it loads en_US.dic, and if that is missing too, the first dictionary in the folder.

To fix the default dictionary instead, set Language to the file name of a dictionary in the default folder. txSpellChecker1 is the resource of the window, which the code-behind gets with FindResource, as As-You-Type Checking shows:

// Use the German dictionary as the default dictionary
txSpellChecker1.Language = "de_DE_frami.dic";

A value ending in .txd loads a user dictionary instead, and "(none)" loads no dictionary at all, for an application that adds only dictionaries of its own. The chosen dictionary has its IsSelectedAsDefault property set to true.

See Which Dictionaries Are There

Two properties answer the two questions a program asks:

  • AvailableDictionaries is an array of the file names in the default folder, whether they are loaded or not, such as de_DE_frami.dic and en_US.dic. It is the list to offer in a language menu of your application.
  • Dictionaries is the DictionaryCollection of the dictionaries that are loaded and used.

Each entry of Dictionaries is a Dictionary: an OpenOfficeDictionary for a Hunspell dictionary, or a UserDictionary for a word list of your own. These properties describe it:

PropertyHolds
NameThe file name, such as en_US.dic
DisplayNameThe name the dialogs show; by default the file name
LanguageThe language, taken from the file name, such as German (Germany) for de_DE_frami.dic; null when the name carries none
IsSpellCheckingEnabledWhether words are checked against it; true by default
IsGetSuggestionsEnabledWhether it provides suggestions; true by default
DictionaryEncodingThe encoding of the dictionary, a System.Text.Encoding

Add a Dictionary

Copy the files of the dictionary into the default folder, as Hunspell and OpenOffice Dictionaries describes. Then create an OpenOfficeDictionary with the file name and add it with Add, for example in the constructor of the window:

using System.Windows;
using TXTextControl.Proofing;
using TXTextControl.WPF.Proofing;

public partial class MainWindow : Window
{
    private readonly TXSpellChecker txSpellChecker1;

    public MainWindow()
    {
        InitializeComponent();

        // The spell checker declared in Window.Resources
        txSpellChecker1 = (TXSpellChecker)FindResource("txSpellChecker1");

        // Check German text as well as English text
        OpenOfficeDictionary german = new OpenOfficeDictionary("de_DE_frami.dic");
        txSpellChecker1.Dictionaries.Add(german);
    }
}

The code works as follows:

  • FindResource returns the spell checker declared in MainWindow.xaml; the OpenOfficeDictionary class comes from the TXTextControl.Proofing namespace, the spell checker from TXTextControl.WPF.Proofing.
  • The constructor takes the name of the .dic or .aff file. A name without a path refers to the default folder. The file is read only when the dictionary is added to the collection.
  • Add loads the dictionary, checks that it is valid, and returns its index in the collection.
  • The new dictionary gets its language from its file name, here German (Germany).

From now on, a word is correct if one of the enabled dictionaries knows it. In a test with the sentence This sentense has a mistake. Dieser Satz hat einen Fehlr., English alone reports sentense, Dieser, Satz, einen and Fehlr; with the German dictionary added, only sentense and Fehlr remain.

To check a text in one language only, pass the language to Check: Check(text, new CultureInfo("de-DE")) uses the German dictionaries and reports the English words of the same sentence. Multilingual Documents and Language Scopes covers texts in several languages.

Check While a Large Dictionary Loads

By default, Add loads a dictionary completely before the spell checker uses it. LoadDictionaryDelayed of the DictionaryCollection changes this: set to true, it loads dictionaries partially when they are added, and the spell checker checks text while the rest is still loading:

// Check text while the German dictionary is still loading
txSpellChecker1.Dictionaries.LoadDictionaryDelayed = true;
txSpellChecker1.Dictionaries.Add(new OpenOfficeDictionary("de_DE_frami.dic"));

The dictionary is loaded when it is added, so set the property before Add. The price is speed: until the dictionary is loaded completely, checking is slower than with a fully loaded one. For the full checking speed, leave the property at its default, false.

Load a Dictionary From Memory

A dictionary doesn't have to be a file in a folder. A second constructor takes the lines of the .dic and the .aff file as string arrays, together with the language, so the dictionary can come from a database or from resources embedded in your assembly:

using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using TXTextControl.Proofing;

private static string[] ReadLines(string resourceName, Encoding encoding)
{
    List<string> lines = new List<string>();

    using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
    using (StreamReader reader = new StreamReader(stream, encoding))
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            lines.Add(line);
        }
    }

    return lines.ToArray();
}

private void AddEmbeddedDictionary()
{
    // The German files are encoded in ISO-8859-1, as the SET line of the .aff file says
    Encoding encoding = Encoding.GetEncoding("ISO-8859-1");

    // The resource names depend on the default namespace and the folder of the files
    OpenOfficeDictionary german = new OpenOfficeDictionary(
        ReadLines("MyApp.Dictionaries.de_DE_frami.dic", encoding),
        ReadLines("MyApp.Dictionaries.de_DE_frami.aff", encoding),
        new CultureInfo("de-DE"));

    txSpellChecker1.Dictionaries.Add(german);
}

Add the two files to the project with the build action Embedded Resource. Read them with the encoding that the SET line of the .aff file names: SET ISO8859-1 for the German dictionary, SET UTF-8 for the English one. The blog article TX Spell .NET 3.0: Loading Dictionaries from Embedded Resources describes the approach.

Switch Off or Remove a Dictionary

A dictionary can stay loaded but play a smaller part:

  • Set IsSpellCheckingEnabled to false, and the dictionary no longer decides whether a word is correct, but can still provide suggestions.
  • Set IsGetSuggestionsEnabled to false, and it checks words but provides no suggestions.

To take a dictionary out entirely, find it with GetItem and pass it to Remove:

Dictionary german = txSpellChecker1.Dictionaries.GetItem("de_DE_frami.dic");

if (german != null)
{
    txSpellChecker1.Dictionaries.Remove(german);
}

GetItem takes the full name, with the extension, and returns null when there is no such dictionary. Add and Remove throw an exception while the spell check dialog is open. Only a user dictionary can be added or removed then, and only while the options dialog that the Options... button of the spell check dialog opened is shown.

React When Dictionaries Change

The spell checker raises DictionaryAdded and DictionaryRemoved whenever the collection changes, whether your code or the user made the change. The Dictionary property of the arguments is the dictionary concerned, for example to update a language menu of your application. Events lists all events.

What Users Can Do

Users switch a dictionary off for checking or for suggestions on the Spell Checking Dictionaries tab of the options dialog, and choose the dictionary the suggestions come from in the Suggestions Dictionary list of the spell check dialog. Options Dialog and Suggestion Controls describe both, and how to hide a dictionary or give it a display name. With the ribbon of TX Text Control, the Settings group of the Proofing tab also has a Load Dictionary button.

Next Steps