Microsoft Communities

Welcome to WindowsClient.net | Sign in | Join

Download the Spell Check control


Spell Checking. 1

1.      Contents 1

2.      Overview. 1

2.1.      Goals 2

2.2.      Non-Goals 2

2.3.      Spec Revision Notes 3

3.      Issues List 3

4.      User Experience. 3

4.1.      Spell Dialog. 3

4.2.      Options Dialog. 4

5.      Design Specification. 5

5.1.      Design. 6

5.2.      Class: SpellCheck 8

5.3.      Class: SpellDialog. 13

5.4.      Class: OptionsDialog. 13

5.5.      Interface: ISpeller 13

5.6.      Class: SpellFactory. 14

5.7.      Class: Word10Speller 15

6.      Localization. 15

6.1.      Overview. 15

6.2.      Default Spell Checking Language. 15

7.      Implementing a New Speller Engine. 15

7.1.      Overview. 15

7.2.      Refactoring Design Notes: 15

8.      Sample SpellCheck Implementation. 15

8.1.      Overview. 16

8.2.      RichTextSpell 16

8.3.      SpellDemo1. 17

 

 

2.  Overview

 

This prototype project will provide a Spell Checking component (SpellCheck) that a WinForms application or custom control can use to provide full-featured spell checking functionality, including the familiar interactive spell checking user experience.  The functionality and user interface exposed by SpellCheck will be very similar to that exposed by Microsoft Outlook – when not using Microsoft Word as an email editor. 

 

Included in this project is a sample implementation of the SpellCheck component in a WinForms custom control called RichTextSpell, which extends the RichTextBox control to add spell checking functionality.  A sample application, SpellDemo1 is provided that uses RichTextSpell in its UI and also accesses the SpellCheck control directly in a variety of ways.

 

SpellCheck implements spell checking functionality internally by using a combination of the factory and adapter design patterns to instantiate an appropriate Speller engine based on the client machine configuration.  This project currently contains a concrete speller implementation that wraps Microsoft Word 10’s proofing API and one that wraps Microsoft Word 11.  This document will discuss how to implement additional spelling engines as well as specific issues and workarounds encountered with the Microsoft Word interop. 

 

The 3 primary objectives that influenced the architecture of this application were:

 

  1. Provide a component that exposes spell checking functionality – including user experience dialogs, that can be consumed via containment in client applications.  SpellCheck is not a WinForms custom control but a component that can be used by a custom control or a WinForms application.   
  2. The spell checking user experience should be similar, if not identical, to that provided by Outlook – not the experience provided by Microsoft Word.  The  auto-detect and auto-correct (i.e. spell checking as you type) features provided by Microsoft Word are not provided by SpellCheck.
  3. The underlying API used to actually perform the spell check, manage the custom dictionary and expose the available proofing languages must be a pluggable component.  

 

2.1.    Goals

  • Provide a spell checking component for use by WinForm applications or WinForm custom control libraries.
  • Provide functionality and user experience to mimic that found in Microsoft Outlook – when not using MS Word as an email editor. 
  • Provide support for the following spell checking capabilities:
    • Select from available proofing languages
    • Ignore all words in upper case.
    • Automatically suggest replacements for mispelled words
    • Ignore one or all occurrences of a mispelled word
    • Change the current word in the original text or change all occurrences of the mispelled word in the original text
    • Undo the changes before completing the spell check.
    • For the Speller implementation using WinWord.exe, manage its lifetime as effeciently as possible and ensure that it behaves correctly when other processes on the machine are utilizing WinWord.exe.
    • Provide the ability to include a custom dictionary in the spell check process.
    • Provide the ability to directly edit the custom dictionary
    • Provide the ability to add words to the custom dictionary at the point they are presented as mispelled words.
  • Create a custom control that extends the RichTextBox to demonstrate the use of the SpellCheck component and a WinForms application to demo the use of the custom control and the component.

 

2.2.    Non-Goals

 

  • Provide pluggable/customizable user interface dialogs for stepping through an interactive spell check and managing spell check options.
  • Provide a spell check component that can be used in a service oriented architecture without showing any modal user dialogs.
  • Provide the dynamic, “as-you-type” spell checking features found in Microsoft Word.
  • Provide grammar and other proofing abilities.
  • Provide multi-threading capabilities within an application domain.  It is assumed that this spell checking experience is a ‘modal’ one and that 2 forms open in the same application will not be concurrently performing spell checks.

 

2.3.    Spec Revision Notes

2.3.1.         New 

 

Wrote spec with input from original Vision and Design documents created by Durstin Selfridge (MCS)

 

 

 

3.  Issues List

 

  1. Word 10 (XP) and Word 11 are currently the only supported Speller engines.  The correct PIA’s must be installed on the client machine.
  2. Word automation will sometimes throw COM exception -2146822898  and display a message indicating that it is unable to access the custom dictionary.  The Word10Speller class does not currently handle this error gracefully – it simply rethrows the error.  I need to work with PSS to come up with a solution/workaround to this error.
  3. The application is not currently localized – the dialogs are English only and error messages are in English only.
  4. The SpellFactory class needs to be enhanced to read from a config file a list of available Speller engines – and then based on a priority from the config file instantiate the correct one.  The  assembly name, class name and priority of the available Speller engines are currently hard coded in SpellFactory – which requires that it be updated as new Speller implementations are added.

 

4.  User Experience

4.1.    Spell Dialog

 

The following dialog will be displayed when a spell check is initiated by a user gesture such as clicking on a “check spelling” button or pressing the  F7 key.   The client application will be responsible for initiating the spell check via the SpellCheck.CheckSpelling() method.

 

 

The original string of text is spell checked one word at a time.  As mispelled words are encountered, this dialog provides the user the opportunity to correct the original text.  It is the responsibility of the SpellCheck component to present this dialog to the user and to fire events that the client application must handle to react to mispelled words and changed words.  This is a modal dialog – the user will not have the opportunity to edit the original text until this dialog is put away.   If no mispelled words are found in the string being spell checked – the dialog will not be presented and it will be the responsibility of the client hosting SpellCheck to display an appropriate notification to the user that the spell check completed successfully with no mispelled words found.

 

The Ignore and Ignore All options do not remember mispelled words from previous spell checks, they only work for the current spell check.   The Undo option simply reverts to the original string and notifies the client application – this is not the way this button behaves in Outlook.  Outlook manages a one word buffer and Undo reverts the last changed word only. The Add button causes the mispelled word to be added to the custom dictionary and the spell check to proceed to the next word.  If the auto suggest option is not on, the Suggest button will be enabled and clicking on it will fill the Suggestions list.   

 

4.2.    Options Dialog

 

The Options Dialog can be presented from a client application, or it can be launched via the “Options …” button in the Spell Dialog. 

 

 

 

The “Always Suggest Replacements”, “Ignore words in UPPERCASE” and Language options are managed at the AppDomain level as static properties of the SpellCheck class and they are also tracked at the SpellCheck instance level.  The SpellCheck API provides a variety of alternatives for managing the default options, the instance options, whether or not changes made during a spell check will become the new defaults, etc.

 

This approach to managing the spell checking options allows for multiple controls throughout an application to track the options at the control level or not.  For example a form might have 3 RichTextSpell controls, one that spell checks in Spanish, one in English and one in French.  Changing the language during a spell check of the Spanish text box to a specific version of Spanish should not reset the language used for the French text box.  There may be other scenarios where the desired behavior would be to persist the change as the new default for the application.  The API allows for this flexibility.

 

Changes to the Custom Dictionary are global to the client machine’s use of the underlying spell checking engine.  This could be further enhanced to allow for more specific control of the custom dictionary at the application level. 

 

The only languages available will be those supported by the underlying spell checking engine on the client machine.  So if Word is the spell checking engine and the Word Proofing tools or MUI Pack are not installed, only the languages supported by the localized version of Word installed will show in the drop down.

 

5.  Design Specification

5.1.    Design

5.1.1.         Overview

 

The SpellChecking assembly contains one public class, SpellCheck.  SpellCheck will display the SpellDialog and the OptionsDialog when required and it will interract with an underlying spell checking engine to receive spell checking services.  The spell checking engine is an implementation of the ISpeller interface.  The internal SpellFactory class – which contains only static members, is responsible for instantiating the correct concrete Speller. 

 

SpellCheck is designed to be created and destroyed with each use, this greatly facilitates the ability for controls on a form to encapsulate SpellCheck without the application having to manage a re-usable instance of SpellCheck.  An entry level developer, Mort, could easily drag a RichTextSpell control (which uses SpellCheck) onto a form and invoke a spell check with one line of code : “richTextSpell1.CheckSpelling()” - without ever having to know about or understand the SpellCheck API.

 

The default, or application wide spell checking options are managed in static properties of the SpellCheck class.  This technique allows these options to be managed across multiple controls and forms without having to manage an application wide object instance.

 

Because SpellCheck manages the underlying Speller engine, which cannot be effeciently created and destroyed every time the F7 key is pressed, the underlying concrete Speller is implemented as a singleton returned from the static SpellFactory.GetSpeller() method.  The first SpellCheck object that gets instantiated by the client application will result in the Speller singleton being created internally, the Speller will remain in memory for the duration of the application – its reference held by a static field within the SpellFactory class.  The SpellCheck constructor requires a reference to a Form as a parameter.  The SpellFactory uses the Form reference to hook the Form.Closed() event where it will dispose the Speller singleton.  Static methods on the SpellCheck class also alow for explicit instantiation and disposal of the underlying speller singleton if greater control is required. 

 

Mort needs to spend some time with the teams senior dev engineer, Einstein,  and understand how the underlying Speller singleton is instanced and disposed and the importance of the Form reference that is provided to the first SpellCheck that is created if he plans on expanding his application to multiple forms that all utilize the SpellCheck component!

 

This design allows for a range of use from simple to complex and it provides the implicit ability for just in time activation of the Speller engine.  If Mort’s customer never performs a spell check because he just won the State Spelling Bee Championship, then winword.exe will never be loaded into memory.

 

5.1.2.         Modality/Threading

SpellCheck implements spell checking as a modal, interactive, user dialog.  There is a basic assumption that the SpellCheck component is only accessed on the STA UI thread. 

 

Because a spell check is an interactive user experience – it by definition blocks on UI input from the modal SpellDialog.  During this process, the underlying Speller singleton is maintaining state for the spell check that is currently in process.  This means that an application cannot open up Form2 and Form3 and allow a user to start a spell check on Form2 and then switch to Form3 and start another spell check.  The underlying Speller singleton will become corrupted.  To defend against this, a rudimentary private static switch will be managed by SpellCheck that will be utilized to prevent this scenario.  Again, it is not expected that more than one thread will ever be involved – only that more than one message loop on the same thread may be processing messages as a result of the modal dialog on a secondary form. 

 

5.1.3.         Spelling Options Management

There are currently 3 options that control spell checking:

  • Ignore All Upper Case
  • Auto Suggest Replacements
  • Language

 

These 3 options are available at the AppDomain level as static read and write properties on the SpellCheck class and they can be overriden on a SpellCheck instance by passing the parameters in to one of the overloaded SpellCheck.CheckSpelling() instance methods.

 

A 3rd technique for managing these options is to expose them as public properties on a custom control – such as in the provided example RichTextSpell – that can be set either in code or at design time.  This allows the options to be managed at the control level, providing a mechanism for more than one control on a form to be spell checked using its own set of options.

 

In addition to a client application or user control programmatically setting these 3 options using these techniques, SpellCheck’s internal OptionsDialog can be presented to the user either explicitly from the main client application via the SpellCheck.ShowDefaultOptions() or SpellCheck.ShowOptions() methods or indirectly via the user clicking on the “Options …” button in the SpellDialog during an interactive spell check.   The following techniques are available for managing the interplay between the default options, the current instance options, and options that may be managed at the custom control level.  

 

  • The SpellCheck.ShowDefaultOptions() method always displays OptionsDialog with the current default options and updates the current default options with any changes from the user.  This method would typically be called from a MainMenu or a tool bar. 
  • The SpellCheck.ShowOptions() method and its overloads shows the Options Dialog with initial values as passed in as parameters and takes a parameter that indicates whether or not changes the user makes should be persisted as the new application defaults.  This method might be used within a GroupBox on a form that also contains a RichTextBox containing the text to be spell checked. 
  • When a spell check is started via the SpellCheck.CheckSpelling() method, various overloads allow the options used for the current spell check to be overridden or the defaults used. 
  • When a spell check is started via the SpellCheck.CheckSpelling() method, a bool parameter indicates whether any option changes the user makes during the spell check should be saved as the new application level defaults – or only used for the current SpellCheck.
  • The client application or custom control can hook the SpellCheck.OptionsChanged method to receive notification that the user changed an option using the Options Dialog.  This allows the client application to track option changes at the control level if required.

5.1.4.         Component Organization

 

SpellChecking.Dll contains the following classes:

 

  • SpellCheck (public)
  • SpellDialog (internal)
  • OptionsDialog (internal)
  • ISpeller (public)
  • SpellFactory (internal)

 

Word10Speller.DLL contains the following classes:

 

·         Word10Speller : ISpeller (internal)

 

Word11Speller.DLL contains the following classes:

 

·         Word11Speller : ISpeller (internal)

 

 

SpellCheckControls.DLL  contains the following classes:

 

·         RichTextSpell : RichTextBox

 

SpellCheck is the only public class (other than the sample RichTextSpell  control implementation), it’s public static and instance methods are the only methods that need to be understood to consume this component.  Word10Speller is the Microsoft Word 10 Speller implementation.  It is delivered as a separate assembly to allow distribution configurability.  It is assumed that each new ISpeller implementation will also be in a new assembly.  SpellFactory dynamically loads Word10Speller.dll and dynamically creates an instance of Word10Speller.    Word10Speller requires that the Office XP Primary Interop Assemblies are installed on the client machine.  SpellCheckControls is a sample custom control library that currently contains one control – RichTextSpell.

 

Because The Word10Speller project contains a reference to the Office XP PIA’s and the Word11Speller class contains a reference to the Office 2003 PIA’s, you can only open these projects and compile on machines that have the appropriate version of Office installed.  These 2 projects are separate from the main solution for this reason.

 

5.2.    Class: SpellCheck

5.2.1.         Overview

This is the only public class in the component.  It’s public static and instance members are the complete public API for the component.  This class is designed to be a short lived object that is created and GC’d as it is used. 

 

As discussed in the Design Overview section above, the first SpellCheck to be created will result in an instance of a Speller engine being created (that is a concrete class that implements ISpeller).  The SpellCheck constructor requires a Form parameter – this should be a reference to a Form that will live for the duration of the process.  SpellFactory uses this reference to hook the Closed event of the Form, where the Speller will be disposed.  This technique allows a just-in-time activation of the underlying spell engine and prevents the spell check engine from being created and destroyed throughout the life of the application.  It is assumed that the Speller engine is a resource intensive API that should not be frequently created and disposed.  If more explicit control over the creation and destruction of the Speller engine is required, the static LoadSpeller and DisposeSpeller methods are available on this class as well.

 

5.2.2.         Responsibilities:

  • Provide the public interface to the spell checking component
  • Uses SpellFactory to create/return the singleton concrete Speller object.
  • Starts a spell check and interacts with the user via the internal SpellOptions dialog to handle all mispelled words.
  • Fires WordMispelled and WordChanged events to notify the client as mispelled words are found and replaced.
  • Tracks all changes the user made in the original string in a new string.
  • Manages internal lists of “Ignore All” words and “Change All” words for the life cycle of a spell check.
  • Manages the default spelling options in static properties, updating them as appropriate if it is requested that option changes made via the options dialog should update defaults.
  • Displays the OptionsDialog when requested from the SpellDialog or via the ShowOptionsDialog public method.
  • Fires the OptionsChanged event to notify client applications that the user has changed the spelling options.
  • Provides static LoadSpeller and DisposeSpeller methods to allow the client application more control over when the Speller engine is loaded and disposed.

 

5.2.3.         Public Static Members

 

public static bool IgnoreUpperCaseDefault

 

Defaults to false.  Gets and Sets the default Ignore Upper Case spelling option.  Access is not thread safe.

 

 

public static bool SuggestReplacementsDefault

 

Defualts to true.  Gets and Sets the default Auto Suggest Replacements spelling option.  Access is not thread safe.

 

public static string DictionaryDefault

 

Defualts to an empty string, which results in the use of the default language for the current thread. (System.Threading.Thread.CurrentThread.CurrentUICulture.Name)

 

public static void CreateSpeller(System.Windows.Forms.Form appMainForm)

 

This method will explicitly force the Speller engine instance to be created.  Use this method to control exactly when the Speller is created instead of relying on the just-in-time activation provided by instantiating the first SpellCheck object in the application. 

 

public static bool IsSpellerAvailable()

 

Gets a flag indicating whether the client machine has access to a spell check engine and thus spell check functionality will be available.  Accessing this property does not cause the underlying Speller object to be created.  The implementation of this property is delegated to the SpellFactory class.

 

 

public static void DisposeSpeller()

 

This method will explicitly force the Speller engine to be disposed.  Use this method to control exactly when the Speller instance disposes its unmanaged resources and itself becomes available for GC. 

 

 

5.2.4.         Public Instance Members

 

Constructor: public SpellCheck(System.Windows.Forms.Form appMainForm)

 

The appMainForm parameter is used only if the singleton Speller instance is not already in memory.  If a Speller does not exist, constructing a SpellCheck will create one and the appMainForm parameter will be used to hook the Form’s closing event where the singleton Speller will be disposed. 

 

Function: public string[] GetAvailableDictionaries()

 

This function calls the Speller.GetAvailableDictionaries method, returning a string array of culture names that the Speller engine is capable of supporting.  This is implemented as a method instead of a property to signify the potentially significant work the Speller may have to perform to discover which languages it supports on the current machine.   It is expected that the Speller engine will cache this information so second and subsequent calls will be performant.

 

Function: public SpellCheckResult CheckSpelling(

string text,

bool optionsDialogUpdatesDefaults,

string dictionary,

bool ignoreUpperCase,

bool suggestReplacement,

Form dialogParent,

bool initialize)

 

This method plus 2 overloads performs a spell check.  When it returns the spell check is complete.  During its execution modal dialogs will potentially be displayed and the WordMispelled, WordChanged and OptionsChanged events will potentiall be fired.  This method must be called on the UI STA thread.  The parameters are described below:

  • text: string containing one or more words to be spell checked.
  • OptionsDialogUpdatesDefaults: any changes the user makes to spelling options during the spell check will or will not update the default options for the AppDomain.
  • dictionary: dictionary to use for the spell check.  If omitted the SpellCheck.DictionaryDefault will be used.
  • ignoreUpperCase: bool to indicate whether words in all upper case should be spell checked or not.  If omitted the SpellCheck.IgnoreUpperCaseDefault will be used.
  • suggestReplacements: bool to indicate whether the list of suggested replacement words will automatically be populated.  If omitted the SpellCheck.SuggestReplacementsDefault will be used.
  • dialogParent: This is the parent form for the modal SpellDialog.
  • initialize: If false, the internal list of words to ignore and the internal dictionary of words to be replaced from the previous spell check will not be reset before starting a new spell check.  This allows a spell check to just spell check the selected text in a TextBox, and then when complete ask the user if they would like to check the rest of the document – while preserving the “Ignore All” and “Replace All” state from the first spell check.   If omitted, defaults to true.

 

Function: public bool ShowOptionsDialog(

System.Windows.Forms.IWin32Window owner,

bool updateDefaults,

string currDictionary,

bool currIgnoreUpperCase,

bool currSuggestReplacements)

 

This method and its overloads is used to display the modal spell check Options dialog directly from a client application.  a typical example of its use would be from a MenuItem click event handler.  If the client application needs to track the new options, then it should hook the SpellCheck.OptionsChanged event before calling this method.

 

  • return value: The function returns true if the options were changed and false if they were not changed.  If the user edits the custom dictionary via the Options Dialog, this will not be reflected in the return value. 
  • owner: parent form for the modal dialog
  • updateDefaults: bool that determines if changes the user makes will update the AppDomain default values managed in the SpellCheck static properties.
  • currDictionary: Dictionary to be shown in the dialog as the current value.  If omitted defaults to SpellCheck.DictionaryDefault.
  • currIgnoreUpperCase: Ignore Upper Case option to be shown in the dialog as the current value.  If omitted defaults to SpellCheck.IgnoreUpperCaseDefault.
  • currSuggestReplacements: Auto Suggest Replacements option to be shown in the dialog as the current value.  If omitted defaults to SpellCheck.SuggestReplacementsDefault.

 

 

Event: public event WordMispelledHandler WordMispelled;

 

Hook this event to receive notification when a mispelled word is found in the original string and presented to the user in the SpellDialog.  If a user chose to ignore all occurences of a mispelled word, or to replace all occurrences of a mispelled word – these words are still processed one at a time as the operation proceeds through the original string but the WordMispelled event will not be fired for the second and subsequent occurrences of these words.   A client will typically use this opportunity to highlight the mispelled word in the original document/TextBox.  The delegate signature and EventArgs are described below:

 

public delegate void WordMispelledHandler(

object sender, WordMispelledEventArgs e);

 

public class WordMispelledEventArgs : System.EventArgs {

      public readonly string  MispelledWord;

      public readonly int StringIndex;

      public readonly int OrigIndex;

}

 

  • MispelledWord: This is the full word that is mispelled.
  • StringIndex: This is the index into the adjusted string of the mispelled word.  The string is adjusted as words are replaced by the user during the spell check operation.
  • OrigIndex: This is the index into the original string of the mispelled word.

 

Event: public event WordChangedHandler WordChanged;

 

Hook this event to receive notification that the user changed the mispelled word.  This event will typically fire after the WordMispelled event if the user chose to change the word.  It will also fire without ever receiving a WordMispelled event if the user selected “Replace All” on a previous word and subsequent occurrences of the word were found.  The delegate signature and EventArgs are described below.

 

public delegate void WordChangedHandler(

object sender, WordChangedEventArgs e);

public class WordChangedEventArgs : System.EventArgs {

      public readonly string OrigWord;

      public readonly string NewWord;

      public readonly int StringIndex;

      public readonly int OrigIndex;

      public readonly string NewText;

}

 

  • OrigWord: This is the original word that was mispelled.
  • NewWord: This is the word the user changed the mispelled word to.
  • StringIndex: This is the zero based index into the adjusted string indicating the starting position of the OrigWord.  The string is adjusted as words are replaced by the user during the spell check operation, which affects the starting position of subsequent words in the string.
  • OrigIndex: This is the zero based index into the original string indicating the starting position of the OrigWord.
  • NewText: This is the entire text string as cumulatively adjusted by the spell check operation so far.

 

 

Event: public event OptionsChangedHandler OptionsChanged

 

Hook this event to receive notification that the user changed the spell checking options via the OptionsDialog.  If a client application needs to track spell checking options at the user control level, for example, it should use this event to receive notification that the options have been changed.  The delegate signature and EventArgs are described below.

 

public delegate void OptionsChangedHandler(

object sender, OptionsChangedEventArgs e);

public class OptionsChangedEventArgs : System.EventArgs {

      public readonly bool OldSuggestReplacements;

      public readonly bool NewSuggestReplacements;

      public readonly bool OldIgnoreUpperCase;

      public readonly bool NewIgnoreUpperCase;

      public readonly string OldDictionary;

      public readonly string NewDictionary;

 

The OptionsChangedEventArgs properties are simply the old and new versions of each spell checking option.

 

5.3.    Class: SpellDialog

5.3.1.         Overview

This is an internal class that inherits directly from Form.  It provides the UI for the spell checking dialog.  This dialog will be shown modally if at least one word is found to be mispelled and it remains visible until the user has proceeded through all mispelled words – or cancelled the spell check.  This class contains no business/process logic – it simply provides the UI and UI event handlers – which delegate work to the SpellCheck object that is managing the current spell check.

 

5.3.2.         Responsibilities:

  • Provide modal UI for spell checking dialog.
  • Delegate all user requests to SpellCheck.

 

5.4.    Class: OptionsDialog

 

5.4.1.         Overview

This is an internal class that inherits directly from Form.  It provides the UI for allowing the user to manage the spell checking options.  Client applications can directly show this options dialog via the SpellCheck.ShowDefaultOptionsDialog() and SpellCheck.ShowOptionsDialog().  It is also shown when the user clicks on the “Options…” button in the SpellDialog.  OptionsDialog delegates work to SpellCheck as appropriate to receive services from the Speller engine.

 

5.4.2.         Responsiblities:

  • Provide modal UI for allowing user to set spell check options
  • Delegate all user requests to SpellCheck.

 

5.5.    Interface: ISpeller

 

5.5.1.         Overview

All concrete Speller implementations (such as the delivered Word10Speller) must implement ISpeller.  The following are the generic responsibilities of all concrete Speller implementations.

 

5.5.2.         Responsibilities:

  • Implement the static IsSpellerAvailable() method that returns true/false to indicate that this Speller is valid for the current machine.  It is expected that this method will check the registry or other resource to determine that it is OK to create and use an instance of this Speller.
  • Accept an original text string potentially containing multiple words and the set of active spell checking options.
  • Implement the Initialize() method to reset internal state (OriginalText, WordIndex, MispelledWord, options, etc) – signaling the start of a new spell check operation.
  • Implement the GetNextMispelledWord() method which must parse through the original text string and spell check one word at a time until a mispelled word is found, taking into consideration the current spelling options of language, ignore upper case and suggest replacements.  The options may be changed by the user during a spell check.
  • Implement the AddToCustomDictionary and LaunchCustomDictionaryEditor methods to manage the users custom dictionary as implemented by a particular Speller engine.  It is assumed that all speller engines will contain the custom dictionary feature, if not, the Speller implementation will have to provide its own.
  • Manage the MispelledWord and WordIndex properties appropriately as a spell check operation proceeds via multiple calls to GetNextMispelledWord().  When GetNextMispelledWord returns, the MispelledWord property should contain the current mispelled word and WordIndex is a zero based index into the original string where the word is found.
  • Expose the Suggestions string array – for mispelled words either automatically, if dictated by the SuggestReplacements option, or when requested via the get accessor of the Suggestions property.  The SuggestReplacements option allows a Speller engine to be more performant if retrieving a list of suggestions for a mispelled word is not required.  Note: the Microsoft Word 10 API always returns a list of suggestions so this implementation always exposes the suggestions list regardless of the SuggestReplacements option.
  • Implement the Dispose(bool) method to free all unmanaged resources.  The Word10Speller uses this opportunity to dispose the background WinWord.exe out-of-process COM server.
  • Expose a list of available spelling dictionaries or languages on the current client machine as a string array of culture names in the format: "<languagecode2>-<country/regioncode2>", where <languagecode2> is a lowercase two-letter code derived from ISO 639-1 and <country/regioncode2> is an uppercase two-letter code derived from ISO 3166.  This is equivalent to the .NET framework CultureInfo classes Name property.  There is an assumption that the default UI culture is a supported language dictionary.

 

5.6.    Class: SpellFactory

5.6.1.         Overview

SpellFactory contains static members only.  It is responsible for creating the correct concrete Speller object and managing it as a singleton.  As new concrete Speller classes are developed that expose other spell checking engines.  See the refactoring note in the section “Implementing a New Speller Engine” below for some work that still needs to be done to this class.

 

5.6.2.         Responsibilities:

  • Determine which concrete Speller class to instantiate.
  • Dynamically create the correct Speller object.
  • Manage the Speller object as a singleton using a private static field to hold it’s reference and prevent it from being GC’d.
  • Hook the Closed event of the client applications main Form where the Speller singleton will be Disposed.
  • Provide an IsSpellerAvailable property that returns a bool indicating whether a Speller can be created on the client machine – without actually creating it.  Note how the actual logic to determine which Speller can be created is delegated to the static IsSpellerAvailable class of each Speller implementation.

 

5.7.    Class: Word10Speller

5.7.1.         Overview

Word10Speller is an implementation of the ISpeller interface.  It wraps Microsoft Word 10 (Office XP) via the Office XP Primary Interop Assemblies.  See the Speller responsibilities above for the functionality implemented by Word10Speller. 

 

5.7.2.         MS Word Interop Issues and Workarounds

 

  

 

6.  Localization

6.1.    Overview

 

UI Localization of the SpellDialog and OptionsDialog classes is not currently fully supported.  The System.Windows.Forms.Form.Localizable property is set to true, causing all controls properties to be managed via localizable satellite resource assemblies but no additional languages other than the default (English – US) have been implemented.  In addition, all MessageBox’s that show error information have not been configured to use localizable resource strings.

 

6.2.    Default Spell Checking Language

 

The default spell checking language is the language from the current thread’s UI culture.  There is currently an assumption that this language is supported as an available dictionary by the underlying Speller engine.

 

 

7.  Implementing a New Speller Engine

7.1.    Overview

 

2 steps are necessary to implement a new Speller engine. 

  1. Write a new class that implements the Speller abstract class.
  2. Update the SpellFactory.GetSpeller method with logic necessary to create the new concrete Speller object.   See Refactoring Design note below.

7.2.    Refactoring Design Notes:

 

This factory logic needs to be engineered to be more dynamic so that this class won’t have to be updated and recompiled when a new Speller is written.  This could be accomplished by providing a config file that contains a list of available Spellers, a priority for which one should be selected, the assembly name to be loaded and class name to be created.  The rest of the logic to support this is already in SpellFactory.

 

 

8.  Sample SpellCheck Implementation

 

8.1.    Overview

 

The sample SpellCheck implementation includes the custom control RichTextSpell which inherits directly from RichTextBox and implements spell checking using the SpellCheck object, and it includes the sample WinForm application SpellDemo1 which uses RichTextSpell and also uses the SpellCheck component directly to display the spellng options dialog from the Tools menu.

 

RichTextSpell can be dragged onto a form and its spell checking options set at design time.  SpellDemo1 is a very simple sample application that includes 2 RichTextSpell controls, the first uses and manages its own spelling options and the second relies on the default options.

 

Because Word10Speller is the only currently implemented Speller, this sample application only works if the client machine has Office XP installed.

 

8.2.    RichTextSpell

RichTextSpell is a RichTextBox that exposes the following additional members:

8.2.1.         Public Instance Members

 

Property: public bool UseLocalSpellingOptions

 

Determines whether to use the local spell checking options managed by this control or the default options scoped to the AppDomain when running a spell check on this control.

 

Property: public bool PersistSpellingOptionChanges

 

Determines whether spelling option changes made by the user during a spell check of this control will be tracked by this control.  If this is set to true, the SpellCheck.OptionsChanged event will be hooked and as the user changes spell check options during a spell check via the OptionsDialog, the Dictionary, IgnoreUpperCase and AutoSuggest properties will be updated.

 

 

Property: public bool SpellingOptionChangesUpdateDefaults

 

Determines whether spell checking options changes made by the user during a spell check of this control should become the new default options for the AppDomain.

 

Property: public bool AutoSuggest

 

Determines whether the spelling suggestions are automatically provided on the Spell Check dialog.

 

Property: public string Dictionary

 

The culture name whose language is to be used during spelling checking in the format: <languagecode2>-<country/regioncode2>

 

 

Property: public bool IgnoreUpperCase

 

Determines whether words entirely in upper case should be ignored.

 

Property: public Form ApplicationMainForm

 

Form that will own the internal spelling engine instance.  Defaults to the form hosting this control

 

Method: public void CheckSpelling()

 

Check spelling on the selected text. If no text is selected, the full text will be spell checked.

 

8.3.    SpellDemo1

 

SpellDemo1 is a very simple WinForms applicaton that demos the following:

 

  1. Main Menu that allows managing the default spelling options
  2. 2 RichTextSpell controls on the same form.
  3. Menu Item with F7 accellerator key that will initiate a spell check for the active RichTextSpell control
  4. One of the 2 RichTextSpell controls manages and remembers its own options instead of using the application defaults.
  5. The other RichTextSpell control uses the defaults, and options changes that are made during a spell check on this control will update the applicaton wide defaults.
  6. Default management (create/dispose) of the underlying speller engine.
  7. Additional UI elements directly on the form that allow the user to manage spell options for one of the controls – without having to display the OptionsDialog.
  8. Because the form load event populates a ComboBox with available languages for display directly on the form, the underlying Speller engine is always loaded at startup.  If a just in time activation of the engine is desirable then the ComboBox displaying the languages could potentially only be initialized with the list on the first drop down.


Page view counter