Working with Word Objects
Working with the Application Object
This chapter examines some of the major objects in the Word object model, starting with the Application object. Many of the objects in the Word object model are very large, and it is beyond the scope of this book to completely describe these objects. Instead, this discussion focuses on the most commonly used methods and properties associated with these objects.
This chapter describes these objects as defined by the primary interop assemblies for Word. You should be aware that VSTO extends some of these objects (Document, Bookmark, XMLNodes, and XMLNode) to add some additional functionality such as data binding support. Part Three of this book, starting with Chapter 13, "The VSTO Programming Model," covers those extensions.
The Application object is the largest object in the Word object model. The Application object is also the root object in the Word object model hierarchy. You can access all the other objects in the object model by starting at Application object and accessing its properties and the properties of objects it returns. The Application object also has a number of application-level settings that prove useful when automating Word.
Controlling Word's Screen Updating Behavior
When your code is performing a set of changes to a document, you might want to set the Application object's ScreenUpdating property to false to prevent Word from updating the screen while your code runs. Turning off screen updating can also improve the performance of a long operation. Setting the property back to true refreshes the screen and allows Word to continue updating the screen.
When changing an application-level property such as ScreenUpdating, always save the value of the property before you change it and set it back to that value when you have finished. Doing so is important because your code will almost never be running by itself inside the Word processit will usually run along side other code loaded into the Word process.
For example, another add-in might be running a long operation on the document, and that add-in might have set the ScreenUpdating property to false to accelerate that operation. That add-in might change the document in some way that triggers an event handled by your code. If your event handler sets the ScreenUpdating property to false and then sets it back to TRue when you have finished, you have now defeated the add-in's attempt to accelerate its own long operation. If instead you save the value of ScreenUpdating before you change it, set ScreenUpdating to false, and then set ScreenUpdating back to its original value, your code will coexist better with other code running inside of Word.
The best way to do this is to use C#'s support for exception handling to ensure that even if an exception occurs in your code, the application-level property you are changing will be set back to its original value. You should put the code to set the application-level property back to its original value in a finally block because this code will run both when no exception occurs and when an exception occurs. Listing 8-1 shows an example of saving the state of the ScreenUpdating property, setting the property to false, and then restoring the original value of the property in a finally block. VSTO declares a class variable called missing of type object that is set to System.Type.Missing. We pass this class variable by reference to all the optional parameters.
Listing 8-1. A VSTO Customization That Uses the ScreenUpdating Property
private void ThisDocument_Startup(object sender, EventArgs e) { Word.Application app = this.Application; bool oldScreenUpdateSetting = app.ScreenUpdating; Word.Range range = this.Range(ref missing, ref missing); try { app.ScreenUpdating = false; Random r = new Random(); for (int i = 1; i < 1000; i++) { range.Text = range.Text + r.NextDouble().ToString(); if (i % 333 == 0) app.ScreenRefresh(): } } finally { app.ScreenUpdating = oldScreenUpdateSetting; } }
In addition to the ScreenUpdating property, Word's Application object has a ScreenRefresh method. You can call this method to force a refresh of the screentypically during an operation when you have set ScreenUpdating to false. For example, you might do the first few steps of an operation and then refresh the screen to show the user the new state of the document and then perform additional steps and refresh the screen again.
Controlling the Dialogs and Alerts That Word Displays
Occasionally, the code you write will cause Word to display dialogs prompting the user to make a decision or alerting the user that something is about to occur. If you find this happening in a section of your code, you might want to prevent these dialog boxes from being displayed so that your code can run without requiring intervention from the user.
You can set the DisplayAlerts property to a member of the WdAlertLevel enumeration. If set to wdAlertsNone, this prevents Word from displaying dialog boxes and messages when your code is running and causes Word to choose the default response to any dialog boxes or messages that might display. You can also set the property to wdAlertsMessageBox to only let Word display message boxes and not alerts. Setting the property to wdAlertsAll restores Word's default behavior.
Be sure to get the original value of this property and set the property back to its original value after your code runs. Use try and finally blocks to ensure that you set the property back to its original value even when an exception occurs.
Changing the Mouse Pointer
During a long operation, you might want to change the appearance of Word's mouse pointer to an hourglass to let users know that they are waiting for some operation to complete. Word's Application object has a System property that returns a System object. The System object has a Cursor property of type WdCursorType that enables you to change the appearance of Word's mouse pointer. You can set it to the following values: wdCursorIBeam, wdCursorNormal, wdCursorNorthwestArrow, or wdCursorWait. Listing 8-2 shows the use of the Cursor property.
Listing 8-2. A VSTO Customization That Sets the Cursor Property
private void ThisDocument_Startup(object sender, EventArgs e) { Word.Application app = this.Application; Word.WdCursorType oldCursor = app.System.Cursor; Word.Range range = this.Range(ref missing, ref missing); try { app.System.Cursor = Word.WdCursorType.wdCursorWait; Random r = new Random(); for (int i = 1; i < 1000; i++) { range.Text = range.Text + r.NextDouble().ToString(); } } finally { app.System.Cursor = oldCursor; } }
Displaying a Message in Word's Status Bar or Window Caption
Word lets you set a custom message in the Word status bar, which is at the lower-left corner of Word's window. StatusBar is a property that can be set to a string value representing the message you want to display in Word's status bar. Unlike most of the other properties in this section, you cannot save the original value of the StatusBar property and set it back after you have changed it. StatusBar is a write-only property and cannot be read.
You can control the text shown in Word's window caption using the Caption property. Caption is a property that can be set to a string value representing the text you want to display in Word's window caption.
Listing 8-3 shows an example of setting the StatusBar property to inform the user of the progress of a long operation. The operation has 1,000 steps, and after every 100 steps the code appends an additional period (.) to the status bar message to indicate to the user that the operation is still in progress.
Listing 8-3. A VSTO Customization That Sets the StatusBar Property
private void ThisDocument_Startup(object sender, EventArgs e) { Word.Application app = this.Application; string status = "Creating Document..."; app.StatusBar = status; Word.Range range = this.Range(ref missing, ref missing); try { app.System.Cursor = Word.WdCursorType.wdCursorWait; Random r = new Random(); for (int i = 1; i < 1000; i++) { range.Text = range.Text + r.NextDouble().ToString(); if (i % 100 == 0) { status += "."; app.StatusBar = status; } } } finally { app.StatusBar = String.Empty; } }
Controlling the Look of Word
Word enables you to control the Word user interface through other properties, such as those listed in Table 8-1. Listing 8-4 shows code behind a VSTO Word document that sets many of these properties.
Listing 8-4. A VSTO Customization and Helper Function That Modifies the Word User Interface
private void ThisDocument_Startup(object sender, EventArgs e) { Word.Application app = this.Application; app.DisplayAutoCompleteTips = GetBool("Auto complete tips?"); app.DisplayRecentFiles = GetBool("Display recent files?"); app.DisplayScreenTips = GetBool("Display screen tips?"); app.DisplayScrollBars = GetBool("Display scroll bars?"); app.DisplayStatusBar = GetBool("Display status bar for active document?"); app.ShowWindowsInTaskbar = GetBool("Multiple windows?"); app.Visible = GetBool("Visible application window?"); app.WindowState = Word.WdWindowState.wdWindowStateNormal; app.Width = 200; app.Height = 300; app.Top = 50; app.Left = 100; } private bool GetBool(string message) { return MessageBox.Show(message, "Word UI Demo", MessageBoxButtons.YesNo) == DialogResult.Yes; }
Property Name |
Type |
What It Does |
---|---|---|
DisplayAuto-CompleteTips |
bool |
Controls whether Word displays auto-complete tips for completing words, phrases, and dates as you type. |
DisplayRecentFiles |
bool |
Controls whether Word displays recently open files in the File menu.You can control how many files Word displays by using the RecentFiles object associated with the Application object and setting the RecentFiles object's Maximum property to a number between 0 and 9. |
DisplayScreenTips |
bool |
Controls whether Word displays pop-up tooltips for text having comments, for footnotes and end notes, and for hyperlinked text. |
DisplayScrollBars |
bool |
Controls whether Word displays the horizontal and vertical scroll bars for all open documents. |
DisplayStatusBar |
bool |
Controls whether Word displays the status bar for the active document. The value of this property can change when the active document changes. |
Height |
int |
Sets the height in points of the main Word window when WindowState is set to wdWindowStateNormal. |
Left |
int |
Sets the left position in points of the main Word window when WindowState is set to wdWindowStateNormal. |
ShowWindowsInTaskbar |
bool |
Sets whether Word creates a window and task bar button for each open document (true) also called SDI mode or uses one window that contains all open document windows (false), which is also called MDI mode. |
Top |
int |
Sets the top position in points of the main Word window when WindowState is set to wdWindowStateNormal. |
Visible |
bool |
Sets whether the Word application window is visible. |
Width |
int |
Sets the width in points of the main Word window when WindowState is set to WdWindowState.wdWindowStateNormal. |
WindowState |
WdWindowState |
Sets whether the main Word window is minimized (wdWindowStateMinimize), maximized (wdWindowStateMaximize) or normal (wdWindowStateNormal). The Width, Height, Left, and Top settings only have an effect when WindowState is set to wdWindowStateNormal. |
Properties That Return Active or Selected Objects
The Application object has a number of properties that return active objectsobjects representing things that are active or selected within Word. Table 8-2 shows some of these properties. Listing 8-5 shows code behind a VSTO Word document that examines these properties.
Listing 8-5. A VSTO Customization and Helper Function That Examine Active Objects
private void ThisDocument_Startup(object sender, EventArgs e) { Word.Application app = this.Application; ShowItem("ActiveDocument", app.ActiveDocument.Name); ShowItem("ActivePrinter", app.ActivePrinter); ShowItem("ActiveWindow", app.ActiveWindow.Caption); ShowItem("NormalTemplate", app.NormalTemplate.Name); ShowItem("Selection", app.Selection.Start.ToString()); } private void ShowItem(string name, string status) { MessageBox.Show(status, name); }
Property Name |
Type |
What It Does |
---|---|---|
ActiveDocument |
Document |
Returns the active Documentthe document that currently has focus within Word. If there are no open documents, an exception is thrown. |
ActivePrinter |
string |
Returns a string for the active printer (for example, "Epson Stylus COLOR 860 ESC/P 2 on LPT1:"). |
ActiveWindow |
Window |
Returns the active Window. If no windows are open, an exception is thrown. |
NormalTemplate |
Template |
Returns a Template object representing the Normal template (normal.dot). |
Selection |
Selection |
Returns a Selection object that represents the current selection or insertion point in the document. |
Properties That Return Important Collections
The Application object has a number of properties that return collections that you will frequently use. Table 8-3 shows several of these properties. Listing 8-6 shows code behind a VSTO Word document that gets the count of these collections and the first item out of each collection.
Listing 8-6. A VSTO Customization and Helper Function That Examines Collection
private void ThisDocument_Startup(object sender, EventArgs e) { Word.Application app = this.Application; Show(String.Format("There are {0} command bars.", app.CommandBars.Count)); Show(String.Format("CommandBar 1 is {0}.", app.CommandBars[1].Name)); Show(String.Format("There are {0} dialog boxes.", app.Dialogs.Count)); Show("Click OK to invoke the About dialog..."); app.Dialogs[Word.WdWordDialog.wdDialogHelpAbout]. Show(ref missing); Show(String.Format("There are {0} open documents.", app.Documents.Count)); object i = 1; Word.Document doc = app.Documents.get_Item(ref i); Show(String.Format("Document 1 is {0}.", doc.Name)); Show(String.Format("There are {0} fonts.", app.FontNames.Count)); Show(String.Format("FontName 1 is {0}.", app.FontNames[1])); Show(String.Format("There are {0} key bindings.", app.KeyBindings.Count)); if (app.KeyBindings.Count > 0) { Show(String.Format("KeyBinding 1 is {0}.", app.KeyBindings[1].Command)); } Show(String.Format("There are {0} recent files.", app.RecentFiles.Count)); Show(String.Format("RecentFile 1 is {0}.", app.RecentFiles[1].Name)); Show(String.Format("There are {0} task panes.", app.TaskPanes.Count)); Show("Click OK to activate the help task pane."); app.TaskPanes[Word.WdTaskPanes.wdTaskPaneHelp]. Visible = true; Show(String.Format("There are {0} templates.", app.Templates.Count)); Show(String.Format("Template 1 is {0}.", app.Templates.get_Item(ref i).FullName)); Show(String.Format("There are {0} windows.", app.Windows.Count)); Show(String.Format("Window 1 is {0}.", Application.Windows.get_Item(ref i).Caption)); } private void Show(string text) { MessageBox.Show(text, "Active Objects"); }
Property Name |
Type |
What It Does |
---|---|---|
CommandBars |
CommandBars |
Returns the CommandBars collection, which lets you modify or add to Word's toolbars and menus. Changes made to toolbars and menus are saved in a template or in a documentuse the CustomizationContext property to set where changes are stored. |
Dialogs |
Dialogs |
Returns the Dialogs collection, which lets you access the built-in Word dialog boxes (of which there are more than 240). You can show a particular dialog box using this collection. |
Documents |
Documents |
Returns the Documents collection, which contains all the documents currently open in Word. |
FontNames |
FontNames |
Returns the FontNames collection, which contains all the fonts that are currently installed and available for use. |
KeyBindings |
KeyBindings |
Returns the KeyBindings collection, which lets you examine, modify, and add key shortcuts that are assigned to Word commands. |
RecentFiles |
RecentFiles |
Returns the RecentFiles collection, which lets you examine and re-open any of the 9 most recently opened files. |
TaskPanes |
TaskPanes |
Returns the TaskPanes collection, which allows you to show or detect which of the 14 built-in task panes are visible. |
Templates |
Templates |
Returns the Templates collection, which lets you examine the installed templates and their properties. |
Windows |
Windows |
Returns the Windows collection, which represents the windows currently open in Word. |
Accessing Items in Collections
As you might have noticed in Listing 8-6, items in a Word collection are accessed in two different ways depending on whether the index into the collection is strongly typed or weakly typed. In the case of the KeyBindings collection, the index is strongly typed as an integer. As such, you can use the index operator ([]) to get to an item in a collection. The code looks like this:
Word.KeyBinding k = Application.KeyBindings[1];
For a collection for which the index into the collection is typed as an object passed by reference, you must use the get_Item method of the collection. The Templates collection is an example of this. It has an index of type object passed by reference. This is because you can either pass a string if you know the name of the template in the collection or you can pass an int for the index of the template in the collection. To get a Template from the Templates collection by int index, you can write this code:
object index = 1; Word.Template t = Application.Templates.get_Item(ref index);
To get a Template from the Templates collection by string name, you can write this code:
object index = "Normal.dot"; Word.Template t = Application.Templates.get_Item(ref index);
Note that in both cases, you must declare an object first and then pass a reference to the object. When passing parameters by reference, you must always declare an object variable first and then pass that declared variable by reference.
Visual Studio is not much help when trying to figure this out. It encourages you to use the index operator even on a collection such as Templates, as shown in Figure 8-1. If you try to use the index operator when the index is passed by reference, however, you receive a compile error.
Figure 8-1. Visual Studio IntelliSense leads you down the wrong path of using the index operator with an object parameter passed by reference.
Furthermore, Visual Studio IntelliSense doesn't display get_Item as a method you can call on the collection in the popup IntelliSense as shown in Figure 8-2 unless you change your settings to show advanced members. To do this, go to the Options dialog by choosing Options… from the Tools menu. In the tree of options, navigate to Text EditorC#General and uncheck the "Hide Advanced Members" check box.
Figure 8-2. Visual Studio IntelliSense does not show the get_Item method when Hide Advanced Members is checked in the Options dialog.
Navigating a Document
The Browser property returns the Browser object, which gives you access to the same functionality available in the browser control that is shown directly below Word's vertical scroll bar, as shown in Figure 8-3.
Figure 8-3. Word's browser control.
To use the Browser object, first set the Browser object's Target property to a member of the WdBrowseTarget enumeration as shown here:
- wdBrowseComment
- wdBrowseEdit
- wdBrowseEndnote
- wdBrowseField
- wdBrowseFind
- wdBrowseFootnote
- wdBrowseGoTo
- wdBrowseGraphic
- wdBrowseHeading
- wdBrowsePage
- wdBrowseSection
- wdBrowseTable
Then use the Browser object's Next and Previous methods to navigate from element to element. Listing 8-7 shows an example of this.
Listing 8-7. A VSTO Customization That Uses the Browser Object
private void ThisDocument_Startup(object sender, EventArgs e) { // Generate some random text in the document. Word.Range r = Range(ref missing, ref missing); System.Text.StringBuilder builder = new System.Text.StringBuilder(); Random rand = new Random(); for (int i = 0; i < 1000; i++) { builder.Append(rand.NextDouble().ToString()); builder.Append(System.Environment.NewLine); } r.Text = builder.ToString(); // Browse by page Application.Browser.Target = Word.WdBrowseTarget.wdBrowsePage; for (int j = 0; j < 10; j++) { Application.Browser.Next(); Application.Selection.Text = String.Format("<<<<<< PAGE {0} >>>>>> ", j); } }
Note that using this approach also changes the selection in the document, which you often do not want to do. Later in this chapter, you learn about the Range object and the various ways you manipulate text with the Range object without changing the selection. The Range object's Goto, GotoNext, and GotoPrevious methods provide the same kind of navigation control that the Browser object provides, without changing the selection.
Working with Word's Options
The Options property provides access to options you might set via the Options dialog. The Options property returns an Options object that has more than 200 properties that you can set.
Listing 8-8 shows an example that gets and then prompts the user to decide whether to change several of the properties on the Options object. The properties set are options from the Save page of Word's Options dialog. Listing 8-8 also shows the Save page in the Options dialog after prompting the user to change options associated with that page.
Listing 8-8. A VSTO Customization That Uses the Options Object and Shows a Built-In Dialog
private void ThisDocument_Startup(object sender, EventArgs e) { Word.Options o = Application.Options; o.CreateBackup = DisplayAndSet( "Always create backup copy", o.CreateBackup); o.AllowFastSave = DisplayAndSet( "Allow fast saves", o.AllowFastSave); o.BackgroundSave = DisplayAndSet( "Allow background saves", o.BackgroundSave); o.SavePropertiesPrompt = DisplayAndSet( "Prompt for document properties", o.SavePropertiesPrompt); o.SaveNormalPrompt = DisplayAndSet( "Prompt to save Normal template", o.SaveNormalPrompt); Application.Dialogs[Word. WdWordDialog.wdDialogToolsOptionsSave]. Show(ref missing); } private bool DisplayAndSet(string settingName, bool settingValue) { string title = "Options Demo"; string checkState = "unchecked."; string action = "check"; if (settingValue == true) { checkState = "checked."; action = "uncheck"; } string message = String.Format( "{0} is {1}. Do you want to {2} it?", settingName, checkState, action); DialogResult r = MessageBox.Show(message, title, MessageBoxButtons.YesNo); if (r == DialogResult.Yes) { return !settingValue; } else { return settingValue; } }
Working with the New and Getting Started Document Task Panes
The NewDocument property returns a NewFile object that lets you customize the New Document and Getting Started task panes. The NewFile object is a shared object in the office.dll PIA that defines types in the Microsoft.Office.Core namespace. The NewFile object is also used by Excel because it shares the same task pane infrastructure. To get to the NewFile object in Excel, use the Excel Application object's NewWorkbook property.
In four sections of the New Document task pane, you can add your own documents, templates, or web addresses. These four sections are the New section, the Templates section, the Recently used templates section, and the Other files section. Figure 8-4 shows the New Document task pane and these four sections. You can also add your own document, template, or web address to the Open section of the Getting Started task pane.
Figure 8-4. The New Document task pane.
The NewDocument property returns a NewFile object that has two methods of interest: Add and Remove. These methods take a file name as a string, a member of the Office.MsoFileNewSection enumeration to specify the section you want to add or remove from, the display name as a string that you want displayed in the task pane, and the action to take when the user clicks the link in the task pane.
The action is specified using a member of the Office.MsoFileNewAction enumeration. Possible actions include msoOpenFile, which opens the document or URL using Internet Explorer; msoCreateNewFile, which creates a new document based on the existing document or template; and msoEditFile, which opens an existing document for editing in Word.
Listing 8-9 shows some code that adds a document or hyperlink to each of the four sections in the New Document task pane. It also adds a document to the Getting Started task pane. To show the New Document task pane, the code uses an unusual techniqueit finds the command bar control for the File > New command (that has an ID of 18) and executes that command. This is done because the New Document task pane cannot be shown in any other wayit is not accessible through the TaskPanes object as you would expect.
The code in Listing 8-9 also handles the Document object's BeforeClose event to remove the added commands from the task pane. As you saw in Chapter 7, "Working with Word Events," the BeforeClose event can be raised multiple times for the same document if the user cancels the save or close of the document or if other BeforeClose event handlers cancel the close. In this case, even if the code in the BeforeClose event runs multiple times, the calls to NewFile.Remove do not raise any exceptions if the item you are trying to remove does not exist.
Note that in Listing 8-9 NewDocument is both a property name and an event name. To get the compiler to not complain and IntelliSense to work, we cast the Application object to the Word._Application interface to let the compiler know we want the property and not the event.
Listing 8-9. A VSTO Customization That Adds Links to the New Document Task Pane
public partial class ThisDocument { private void ThisDocument_Startup(object sender, EventArgs e) { Office.NewFile newFile = ((Word._Application)Application).NewDocument; newFile.Add(@"c:foo.doc", Office.MsoFileNewSection.msoNew, "msoNew msoEdit", Office.MsoFileNewAction.msoEditFile); newFile.Add(@"c:foo.doc", Office.MsoFileNewSection.msoNewfromTemplate, "msoNewFromTemplate msoCreateNewFile", Office.MsoFileNewAction.msoCreateNewFile); newFile.Add(@"c:foo.doc", Office.MsoFileNewSection.msoNewfromExistingFile, "msoNewFromExistingFile msoCreateNewFile", Office.MsoFileNewAction.msoCreateNewFile); newFile.Add(@"http://www.microsoft.com", Office.MsoFileNewSection.msoBottomSection, "msoBottomSection msoOpenFile", Office.MsoFileNewAction.msoOpenFile); newFile.Add(@"c:foo.doc", Office.MsoFileNewSection.msoOpenDocument, "msoOpenDocument msoEdit", Office.MsoFileNewAction.msoEditFile); // Execute the "New" command found // in the File menu to show // the new document task pane. Application.CommandBars.FindControl( 1, 18, missing, missing).Execute(); } private void ThisDocument_BeforeClose(object sender, System.ComponentModel.CancelEventArgs e) { Office.NewFile newFile = ((Word._Application)Application).NewDocument; newFile.Remove(@"c:foo.doc", Office.MsoFileNewSection.msoNew, "msoNew msoEdit", Office.MsoFileNewAction.msoEditFile); newFile.Remove(@"c:foo.doc", Office.MsoFileNewSection.msoNewfromTemplate, "msoNewFromTemplate msoCreateNewFile", Office.MsoFileNewAction.msoCreateNewFile); newFile.Remove(@"c:foo.doc", Office.MsoFileNewSection.msoNewfromExistingFile, "msoNewFromExistingFile msoCreateNewFile", Office.MsoFileNewAction.msoCreateNewFile); newFile.Remove(@"http://www.microsoft.com", Office.MsoFileNewSection.msoBottomSection, "msoBottomSection msoOpenFile", Office.MsoFileNewAction.msoOpenFile); newFile.Remove(@"c:foo.doc", Office.MsoFileNewSection.msoOpenDocument, "msoOpenDocument msoEdit", Office.MsoFileNewAction.msoEditFile); } private void InternalStartup() { this.Startup += new EventHandler(ThisDocument_Startup); this.BeforeClose += new System.ComponentModel.CancelEventHandler( this.ThisDocument_BeforeClose); } }
Working with the File Save Format Options
The DefaultSaveFormat property enables you to change the default format that Word saves in when the user creates a new document and then saves it. For example, setting DefaultSaveFormat to "Text" will cause Word to save new files in a text only format. Setting DefaultSaveFormat to an empty string will cause Word to save in the default file format.
You can also specify that one of the installed file converters be used as the default save format. The FileConverters property returns a collection of available file converters that save in formats such as Works format. Each FileConverter object in the FileConverters collection has a ClassName property that returns a string. You can set the DefaultSaveFormat property to the string returned by the ClassName property of the FileConverter you want to use as the default save format. For example, the Works 6.0 & 7.0 FileConverter object has a ClassName property that returns "wks632". Setting DefaultSaveFormat to "wks632" will make Works 6.0 & 7.0 the default save format.
Working with File Dialogs
Word provides several properties and methods that enable you to change the directory that the Open and Save dialog default to. The ChangeFileOpenDirectory method takes a string parameter that is the new path that you want the Open and Save dialog to default to. A change made using this method only lasts until the user exits the application or ChangeFileOpenDirectory is called again during the run of the application.
To permanently change the directory that the Open and Save dialog default to, you can use the Options object's DefaultFilePath property. Prompt the user if you permanently change a setting like this. Users usually do not appreciate it when programs change their settings without asking their permission first.
If you need to display a customized file dialog, you can use the get_FileDialog method, which returns a FileDialog object you can customize and show to the user. The get_FileDialog method takes a required parameter of type Office.MsoFileDialogType, which can be one of the following enumerated values: msoFileDialogOpen, msoFileDialogSaveAs, msoFileDialogFilePicker, or msoFileDialogFolderPicker.
Listing 8-10 shows an example that gets a FileDialog of type msoFileDialogFilePicker and modifies it to let the user select files from the desktop to copy to their C: directory. There are several things to observe in this example. First, the FileDialog object has several properties that enable you to customize the dialog, including AllowMultiSelect, ButtonName, InitialFileName, InitialView, and Title.
Listing 8-10 also illustrates that showing the FileDialog using the Show method does not do any Word action such as opening files when the user clicks the default button. Instead, it returns an integer value that is 1 if the user clicked the default button and 0 if the user clicked the Cancel button. If the user clicks the default button and Show returns a 1, the code iterates over the FileDialog's SelectedItems collection to get the files that the user selected to copy.
Listing 8-10. A VSTO Customization That Modifies Word's File Dialog
private void ThisDocument_Startup(object sender, EventArgs e) { Office.FileDialog f = Application.get_FileDialog( Office.MsoFileDialogType.msoFileDialogFilePicker); f.AllowMultiSelect = true; f.ButtonName = @"Copy to C:"; f.InitialFileName = System.Environment. GetFolderPath(Environment.SpecialFolder.Desktop); f.InitialView = Office.MsoFileDialogView.msoFileDialogViewList; f.Title = @"Select files to copy to c:"; int result = f.Show(); if (result == -1) { foreach (string s in f.SelectedItems) { System.IO.FileInfo fileName = new System.IO.FileInfo(s); System.IO.File.Copy(fileName.FullName, @"c:" + fileName.Name); } } }
User Information
Word's Application object has several properties that return user information including UserName, UserAddress, and UserInitials. These string properties return the user information the user entered when installing the product. The user can also edit this information by going to Word's Options dialog and editing the fields under the User Information tab.
Checking Grammar and Spelling
Word provides some application-level methods that enable you to use Word's grammar and spelling engine to check arbitrary strings. CheckGrammar is a method that takes a string and returns a bool value. It returns true if the string is deemed grammatically correct by Word's grammar checker and false if it is not. CheckSpelling is a method that that takes a string and returns TRue if the string is spelled correctly, false if the string is not spelled correctly.
The GetSpellingSuggestions method can take a single word that is misspelled and suggest possible correct spellings for the word. It takes a required string that is the word to check. It also takes a number of optional parameters. It returns a SpellingSuggestions collection that contains possible correct spellings.
Listing 8-11 shows a VSTO customization that uses these application-level grammar and spelling checking functions. In Listing 8-11 optional arguments cause the code to get a little verbose. The CheckSpelling and GetSpellingSuggestions methods have multiple optional parametersmany of which are used to specify additional dictionaries to consult.
Listing 8-11. A VSTO Customization That Checks Grammar and Spelling
private void ThisDocument_Startup(object sender, EventArgs e) { string badString = "This are grammatically incorrect."; string goodString = "This is grammatically correct."; string badString2 = "I cain't spel."; string goodString2 = "I can spell."; string singleWord = "spel"; MessageBox.Show(String.Format( "{0} CheckGrammar returns {1}.", badString, Application.CheckGrammar(badString))); MessageBox.Show(String.Format( "{0} CheckGrammar returns {1}.", goodString, Application.CheckGrammar(goodString))); MessageBox.Show(SpellingHelper(badString2)); MessageBox.Show(SpellingHelper(goodString2)); MessageBox.Show(String.Format( "Getting spelling suggestions for {0}.", singleWord)); Word.SpellingSuggestions suggestions = Application.GetSpellingSuggestions( singleWord, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing); foreach (Word.SpellingSuggestion s in suggestions) { MessageBox.Show(s.Name); } } private string SpellingHelper(string phrase) { bool correctSpelling = Application.CheckSpelling( phrase, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing); if (correctSpelling) return String.Format("{0} is spelled correctly.", phrase); else return String.Format("{0} is spelled incorrectly.", phrase); }
Exiting Word
The Quit method can be used to exit Word. If any unsaved documents are open, Word prompts the user to save each unsaved document. When users are prompted to save, they get a dialog box that has a Cancel button. If the user clicks Cancel, or if any code is running that is handling the Application.DocumentBeforeClose event sets the cancel parameter to TRue, Word does not quit.
Setting the DisplayAlerts property to wdAlertsNone will not suppress Word prompting the user to save. Fortunately, the Quit method takes three optional parameters that can control whether Word prompts the user to save. The first optional parameter, called SaveChanges, is of type object and can be passed a member of the WdSaveOptions enumeration: wdDoNotSaveChanges, wdPromptToSaveChanges, or wdSaveChanges. The second optional parameter, called OriginalFormat, is of type object and can be passed a member of the WdOriginalFormat enumeration: wdOriginalDocumentFormat, wdPromptUser, or wdWordDocument. This parameter controls Word's behavior when saving a changed document whose original format was not Word document format. The final optional parameter is called RouteDocument and is of type object. Passing true for this parameter routes the document to the next recipient if a routing slip is attached.
Listing 8-12 shows a VSTO application that calls Quit without saving changes. It also illustrates an issue where the Quit method and the Quit event collide on the Application object. To get the compiler to not complain and IntelliSense to work, the code casts the Application object to a Word._Application interface to let the compiler know to invoke the method and not the event.
Listing 8-12. A VSTO Customization That Calls Quit
private void ThisDocument_Startup(object sender, EventArgs e) { Range(ref missing, ref missing).Text = "Sample text"; object saveChanges = false; ((Word._Application)Application).Quit( ref saveChanges, ref missing, ref missing); }