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
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:
- 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.
- 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.
- 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.
- 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.
- 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.1.
New
Wrote spec with input from original Vision and Design documents created by Durstin
Selfridge (MCS)
- Word 10 (XP) and Word 11 are currently the only supported Speller
engines. The correct PIA’s must be installed on the client machine.
- 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.
- The application is not currently localized – the dialogs are English
only and error messages are in English only.
- 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.
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.
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.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.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.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.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.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.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.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
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.
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.
2 steps are necessary to implement a new Speller engine.
- Write a new class that implements the Speller abstract class.
- Update the SpellFactory.GetSpeller method with logic necessary
to create the new concrete Speller object. See Refactoring Design note below.
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.
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.
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.
SpellDemo1 is a very simple WinForms applicaton that demos the following:
- Main Menu that allows managing the default spelling options
- 2 RichTextSpell controls on the same form.
- Menu Item with F7 accellerator key that will initiate a spell
check for the active RichTextSpell control
- One of the 2 RichTextSpell controls manages and remembers its
own options instead of using the application defaults.
- 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.
- Default management (create/dispose) of the underlying speller
engine.
- 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.
- 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.