Using a Custom Spell-Check Engine

Daniel writes desktop software for a clinical-trials company. Their drug-naming database is a curated list of seventy thousand compound names, brand candidates, and pharmacological abbreviations that the regulatory team updates twice a week. When a clinician types a trial report inside the company's desktop app, the editor must accept those seventy thousand terms as correct and flag the ones outside the list. No off-the-shelf English dictionary will ever know what "Briletumab-7XQ" is.

The built-in spell checker is excellent at general English. It is not, and cannot reasonably be, an expert on Daniel's domain. So Daniel takes over the spell-check pipeline entirely. The editor exposes a five-method interface, ISpellCheckerEngine, and once he hands his own implementation to the control every Spell, Suggest, and Add call -- inline squiggles and dialog mode alike -- is routed through his code instead.

Architecture diagram showing the SpiceLogic WinForms HTML Editor delegating Spell and Suggest calls through a custom ISpellCheckerEngine implementation to an external terminology service.

The interface he has to implement

Five methods. The editor never calls anything else.

namespace SpiceLogic.HtmlEditor.Abstractions.Entities.SpellCheck;
public interface ISpellCheckerEngine
{
    void Initialize(string dictionaryPath, string affixPath, string userDictionaryPath);
    bool Spell(string word);
    IEnumerable<string> Suggest(string word, int? max = null);
    void AddToUserDictionary(string word);
    void Dispose();
}
Namespace SpiceLogic.HtmlEditor.Abstractions.Entities.SpellCheck
    Public Interface ISpellCheckerEngine
        Sub Initialize(dictionaryPath As String, affixPath As String, userDictionaryPath As String)
        Function Spell(word As String) As Boolean
        Function Suggest(word As String, Optional max As Integer? = Nothing) As IEnumerable(Of String)
        Sub AddToUserDictionary(word As String)
        Sub Dispose()
    End Interface
End Namespace

Plugging it in

Two assignments at startup and the editor uses the new engine for both inline squiggles and the dialog walk-through. The SpellChecker selection on the control is the switch that tells the control "use the custom plug-in I just gave you instead of the built-in one":

public partial class TrialReportForm : Form
{
    public TrialReportForm(TerminologyServiceClient service)
    {
        InitializeComponent();
        editor.SpellCheckOptions.CustomSpellCheckerEngine = new ClinicalTermsEngine(service);
        editor.SpellChecker = SpellCheckerEngineTypes.Custom;
        editor.SpellCheckOptions.FireInlineSpellCheckingOnKeyStroke = true;
    }
}
End Sub

Public Partial Class TrialReportForm
    Inherits Form
    Public Sub New(service As TerminologyServiceClient)
        InitializeComponent()
        editor.SpellCheckOptions.CustomSpellCheckerEngine = New ClinicalTermsEngine(service)
        editor.SpellChecker = SpellCheckerEngineTypes.Custom
        editor.SpellCheckOptions.FireInlineSpellCheckingOnKeyStroke = True

From here on, every word in the editor is checked against the regulatory service. "Briletumab-7XQ" no longer carries a red squiggle. "Briletumab-7XR," which does not exist in the regulatory database, does.

Trial report editor in the SpiceLogic WinForms HTML Editor accepting industry-specific compound names as valid while flagging an unknown variant via the custom ISpellCheckerEngine.

When the simple engine isn't enough

Daniel's first deployment worked, but two refinements followed once real clinicians started using it. The regulatory service occasionally goes down for maintenance, and a network blip should not make every word in a report light up red. He wraps Spell in a fail-open fallback: when the service is unreachable, the engine returns true and the report is treated as clean until the connection recovers. The second refinement was performance: the daily report runs in the thirty-thousand-word range, and his initial implementation made one HTTP call per unknown word for suggestions. The fix was to cache suggestions for the most recent few hundred mis-hits per session and to honour the max hint scrupulously -- inline suggestions ask for three, the dialog asks for ten.

Patterns this same plug-in serves

Daniel's clinical-terms story is one shape; the same interface answers several others. A corporate authoring team can route every spell call through their company terminology server. A legal-tech vendor can plug in a contracts-and-citation dictionary. An email-AI startup can hand the editor a backend-driven engine that does grammar, style, and tone in addition to spelling. None of these need to ship a Hunspell binary, and none of them give up the editor's inline squiggle UI -- the same engine drives both modes the moment SpellChecker = SpellCheckerEngineTypes.Custom is set.

Sample to start from

A runnable end-to-end sample lives in the product download. Look for the Custom Spell Checker project under the installation's Samples folder -- it implements ISpellCheckerEngine against a small in-memory vocabulary and wires it into a WinFormHtmlEditor exactly as shown above.

Last updated on May 15, 2026