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.