# User Dictionaries

> Create, fill and save user dictionaries in Windows Forms with UserDictionary: AddWord, Save, UserDictionaryWordAdded, the .txd format and SET, WORDCHARS, ICONV.

- **Product:** TX Spell .NET for Windows Forms
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Spell .NET for Windows Forms > Dictionaries and Languages > User Dictionaries
- **2952 words**
- **Web URL:** https://docs.textcontrol.com/tx-spell-dotnet-winforms/dictionaries/user/
- **LLMs URL:** https://docs.textcontrol.com/tx-spell-dotnet-winforms/dictionaries/user/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-spell-dotnet-winforms/dictionaries/user/llms-full.txt

---

Brand names, product names, abbreviations and the vocabulary of a trade are correct, but no dictionary knows them. A *user dictionary* is the place for such words: a plain word list that sits beside the language dictionaries, that users fill with **Add To Dictionary**, and that your code can create, fill and save. Once saved, the words are accepted in the next session as well.

### What a User Dictionary Is

A user dictionary is a text file with the extension *.txd*: usually a line that names the encoding, then one word per line. TX Spell .NET loads it as a [UserDictionary](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/userdictionary/llms-full.txt), and checks every text against it together with the other dictionaries in [Dictionaries](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/txspellchecker/dictionaries-property/llms-full.txt). Any number of user dictionaries can be loaded at the same time.

A user dictionary does two jobs:

- **It accepts words.** A word in a user dictionary is never reported as misspelled, whether the user types it or `Check` finds it.
- **It receives words.** **Add To Dictionary** in the context menu and in the spell check dialog adds the current word to every user dictionary whose [IsEditable](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/userdictionary/iseditable-property/llms-full.txt) property is `true` and whose language matches the word. Without such a dictionary, the command is disabled. [HasEditableUserDictionaries](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/dictionarycollection/haseditableuserdictionaries-property/llms-full.txt) of the `Dictionaries` collection tells your code whether the collection holds an editable user dictionary at all, for example to enable an **Add To Dictionary** command of your own.

The *UserDictionary* sample of the setup edits a user dictionary with a text box and a list: every word added there is accepted in the `RichTextBox` on the left.

![The UserDictionary sample: a RichTextBox with the misspelled word "wroong" underlined, and a User Dictionary panel with the text box TXTextControl, the buttons Add word and Remove word, and a list with the words RichTextBox and TXSpell.](https://docs.textcontrol.com/assets/img/tx-spell-dotnet-winforms/user-dictionary-sample.a5ca73c5.webp)

### Add a User Dictionary That Keeps Its Words

> Warning
>
> **Unsaved Words.** A user dictionary exists only in memory until you save it.

The following form loads the user dictionary of the last session when it opens, and saves it every time a word is added or removed. The form has a `TextControl` connected to a `TXSpellChecker` called *txSpellChecker1*, as in [Create Your First Windows Forms Application](https://docs.textcontrol.com/tx-spell-dotnet-winforms/getting-started/tx-text-control/first-application/llms-full.txt):

```csharp
using System;
using System.Globalization;
using System.IO;
using System.Windows.Forms;
using TXTextControl.Proofing;

public partial class Form1 : Form
{
    private readonly UserDictionary userDictionary;

    // A folder the user can write to
    private readonly string userDictionaryPath = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
        "MyCompany", "MyApp", "en_custom.txd");

    public Form1()
    {
        InitializeComponent();

        // Load the words of the last session, or start with an empty user dictionary
        userDictionary = File.Exists(userDictionaryPath)
            ? new UserDictionary(userDictionaryPath)
            : new UserDictionary();

        txSpellChecker1.Dictionaries.Add(userDictionary);
        userDictionary.Language = new CultureInfo("en-US");
        userDictionary.Name = "User Dictionary";

        // Words every user needs
        userDictionary.AddWord("TXTextControl");

        // Save whenever a word is added or removed, for example with Add To Dictionary
        txSpellChecker1.UserDictionaryWordAdded += (sender, e) => SaveUserDictionary();
        txSpellChecker1.UserDictionaryWordRemoved += (sender, e) => SaveUserDictionary();
        FormClosing += (sender, e) => SaveUserDictionary();
    }

    private void SaveUserDictionary()
    {
        Directory.CreateDirectory(Path.GetDirectoryName(userDictionaryPath));

        if (!userDictionary.Save(userDictionaryPath))
        {
            MessageBox.Show("The user dictionary could not be saved.");
        }
    }
}
```

#### What the Code Does

- The [constructor](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/userdictionary/constructor/llms-full.txt) with a path loads an existing *.txd* file. The constructor without arguments creates an empty user dictionary. The code checks first whether the file exists, because in the first session there is none.
- [Add](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/dictionarycollection/add-method/llms-full.txt) puts the user dictionary into the collection. Only then does it take part in checking, and only then do its methods have an effect.
- [Language](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/dictionary/language-property/llms-full.txt) ties the dictionary to US English, so that **Add To Dictionary** adds English words to it. A file name that starts with a locale, such as *en\_custom.txd*, sets the language as well when the dictionary is loaded from the default folder.
- [Name](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/dictionary/name-property/llms-full.txt) names the user dictionary. The options dialog and the dictionary list of the spell check dialog show it, because [DisplayName](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/dictionary/displayname-property/llms-full.txt) defaults to the name.
- [AddWord](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/userdictionary/addword-method/llms-full.txt) adds a word in code. A word that is already there is not added twice.
- [UserDictionaryWordAdded](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/txspellchecker/userdictionarywordadded-event/llms-full.txt) and [UserDictionaryWordRemoved](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/txspellchecker/userdictionarywordremoved-event/llms-full.txt) fire when a word is added to or removed from a user dictionary, including through **Add To Dictionary**.
- [Save](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/userdictionary/save-method/llms-full.txt) writes the words to the file and returns `false` when nothing was written, for example because the name doesn't end with *.txd*. An existing file is overwritten. Afterward, [FilePath](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/userdictionary/filepath-property/llms-full.txt) holds the path.

The folder below *AppData* is one the user can always write to; the installation folder of an application usually isn't. A name without a path, such as `Save("en_custom.txd")`, saves into the default dictionary folder.

### Add and Remove Words in Code

Besides `AddWord`, a `UserDictionary` has these methods to change and read its words:

| Member | Does |
|---|---|
| [RemoveWord](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/userdictionary/removeword-method/llms-full.txt) | Removes one word; returns `false` if the word wasn't there |
| [RemoveAllWords](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/userdictionary/removeallwords-method/llms-full.txt) | Removes all words |
| [ToArray](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/userdictionary/toarray-method/llms-full.txt) | Returns the entries as a string array, for example to show them in a list |

`AddWord`, `RemoveWord` and `RemoveAllWords` have no effect, and return `false`, while the dictionary is not in `Dictionaries` or while `IsEditable` is `false`. `Save` has a second overload, `Save(out string[])`, which returns the file's lines as an array instead of writing a file, to store them in a database; the constructor that takes a string array and a language loads them again.

### The File Format

The file that `Save` writes for the form above, after the user has added *TXSpell* with **Add To Dictionary**, looks like this:

```text
SET utf-8
WORDCHARS @
TXSpell
TXTextControl
```

The first line, `SET`, names the encoding of the file. When a file has no `SET` line and the [DictionaryEncoding](https://docs.textcontrol.com/tx-spell-dotnet-winforms/reference/txtextcontrol-proofing/dictionary/dictionaryencoding-property/llms-full.txt) property doesn't name one either, TX Spell .NET reads it with the current ANSI code page of the operating system, so write the line to keep words with accents and umlauts intact. The words follow, one per line, in alphabetical order.

At the top of the file, before the words, a user dictionary can define how text is split into words. These flags are the same ones Hunspell dictionaries use:

| Flag | Defines |
|---|---|
| `SET` | The encoding of the file |
| `WORDCHARS` | Characters that count as part of a word, beyond letters and digits |
| `BREAK` | Characters that are both part of a word and a delimiter |
| `ICONV` | A character that is replaced by another before a word is checked |

This user dictionary makes hyphens, apostrophes and dashes part of words, and reads the typographic apostrophe as a straight one and the em dash as a hyphen:

![A user dictionary file with the lines SET UTF-8, WORDCHARS and BREAK with apostrophes, hyphen, plus, period and em dash, two ICONV lines, and the words character, doesn't, hyphen-minus, include, text, that and the.](https://docs.textcontrol.com/assets/img/tx-spell-dotnet-winforms/user-dictionary-file.75217803.webp)

With it, the sentence *That text doesn’t include the hyphen—minus character '-'.*, written with a typographic apostrophe, has no misspelled words. Without the flags, *doesn*, *hyphen* and *minus* are reported. The same file edited next to TX Text Control Words:

![The file medical.txd open in Visual Studio Code with the flags SET, WORDCHARS, BREAK and ICONV and a word list, in front of TX Text Control Words with the sentence That text doesn't include the hyphen—minus character.](https://docs.textcontrol.com/assets/img/tx-spell-dotnet-winforms/user-dictionary-flags.feee6ff8.webp)

### Let Users Manage Their User Dictionaries

The options dialog of TX Spell .NET has a **User Dictionaries...** button on its **Spell Checking Dictionaries** tab, which opens a dialog in which users edit, create, add and remove user dictionaries. [The Spell Checking Dictionaries Tab](https://docs.textcontrol.com/tx-spell-dotnet-winforms/user-interface/options-dialog/#the-spell-checking-dictionaries-tab) describes it.

### Keep Words the User Can't Change

A user dictionary with `IsEditable` set to `false` still accepts its words, but **Add To Dictionary** doesn't write to it and users can't change it. That makes it an ignore list for names and terms your application brings along. [Ignore Settings](https://docs.textcontrol.com/tx-spell-dotnet-winforms/spell-checking/ignore-settings/#keep-an-ignore-list) shows the code; fill the list before you set `IsEditable` to `false`.

### Words From Other Spell Checkers

Most other spell checkers can export their user dictionaries as text word lists. Add a `SET` line with their encoding at the top, for example `SET iso-8859-1`, save the file with the extension *.txd*, and TX Spell .NET loads it. The blog article [Converting 3rd-party User Dictionaries to TX Spell .NET](https://www.textcontrol.com/blog/2012/01/03/converting-3rd-party-user-dictionaries-to-tx-spell-net/) describes this for RapidSpell and offers a converter for ComponentOne SpellChecker dictionaries.

### Next Steps

- [Loading and Managing Dictionaries](https://docs.textcontrol.com/tx-spell-dotnet-winforms/dictionaries/managing/llms-full.txt): the collection the user dictionaries belong to.
- [Options Dialog](https://docs.textcontrol.com/tx-spell-dotnet-winforms/user-interface/options-dialog/llms-full.txt): the dialogs in which users manage dictionaries.
- [Events](https://docs.textcontrol.com/tx-spell-dotnet-winforms/spell-checking/events/llms-full.txt): the other events of the spell checker.

---

## Nearby

- **Previous:** [Loading and Managing Dictionaries](https://docs.textcontrol.com/tx-spell-dotnet-winforms/dictionaries/managing/llms-full.txt)
- **Next:** [Multilingual Documents and Language Scopes](https://docs.textcontrol.com/tx-spell-dotnet-winforms/dictionaries/multilingual/llms-full.txt)
