One More Word

 

David Shank
Microsoft Corporation

December 7, 2000

In last month's column, I talked about the basics of working with Microsoft Word documents programmatically, and discussed how to work with the contents of a document using the Range object. I got a lot of interesting feedback on that column, along with requests for some additional information. Specifically, readers asked about working with documents using the Selection object and working with bookmarks programmatically. So, this month I will talk about the Selection object, provide some information on the differences between the Selection object and the Range object, and give you some information on programmatically working with bookmarks in Word documents.

Working with the Selection Object

The Selection object represents the currently selected text in a Word document. The Selection object is always present in a document; if no text is selected, it represents the insertion point. Unlike the Range object, there can only be one Selection object at a time.

You can use the Selection object's Type property to get information about the state of the current selection. For example, if there is no current selection, the Selection object's Type property returns wdSelectionIP. The Type property will return one of nine values represented by the wdSelectionType enumerated constants.

You use the Selection property to return a Selection object. The Selection property is available from the Application, Window, and Pane objects. However, because the Selection property is global, you can refer to it without referencing another object first. For example, the following sample code illustrates how you use the Selection property to get information about the currently selected text:

Sub SelectionCurrentInfo()
   Dim strMessage As String

   With Selection
      If .Characters.Count > 1 Then
         strMessage = "The Selection object in '" _
         & ActiveDocument.Name & "' contains " _
         & .Characters.Count & " characters, " _
         & .Words.Count & " words, " & .Sentences.Count _
         & " sentences, and " & .Paragraphs.Count _
         & " paragraphs."
         MsgBox strMessage
      End If
   End With
End Sub

The next example shows how you can use the Range property of the Selection object to replace currently selected text:

Sub ChangeSelectedText()
   Dim rngDocContent   As Word.Range
   Dim strNewText      As String

   If Selection.Type = wdSelectionIP Then
       MsgBox "Please select a word to replace before running " _
         & "this procedure."
      Exit Sub
   Else
      strNewText = InputBox("Enter text to replace '" _
         & Selection.Text & "'.", "Replace existing text")
      If Len(strNewText) = 0 Then Exit Sub
   End If
   Set rngDocContent = Selection.Range
   rngDocContent.Text = strNewText
End Sub

When it comes to manipulating text, the Selection and Range objects have many methods and properties in common. However, the Selection object has a unique set of methods for manipulating text. These are the TypeText, TypeParagraph, and TypeBackspace methods. You use these methods to enter or remove text, and to insert paragraph marks in a Selection object. In order to get the results you expect, there are a few things you need to understand about these methods.

The TypeMethodName methods may delete existing text, depending on the value of the Options object's ReplaceSelection property. The ReplaceSelection property returns the value of the Typing replaces selection option on the Edit tab in the Options dialog box. When the ReplaceSelection property is True, using any of the TypeName methods will result in the currently selected text being replaced. When the ReplaceSelection property is False, the TypeText and TypeParagraph methods add text or a paragraph mark to the beginning of the current selection. In addition, when the ReplaceSelection property is False, the TypeBackspace method behaves the same as the Collapse method of a Range or Selection object when the wdCollapseStart constant is specified in the Direction argument. The Collapse method collapses a range or selection so that its starting point and ending point are the same.

Comparing the Selection Object and the Range Object

In many ways, the Selection object is like a Range object. The Selection object represents an arbitrary portion of a document. It has properties that represent characters, words, sentences, paragraphs, and other objects in a Word document. The main difference is that when you use the Range object, it's not necessary to first select the text. In addition, there can be only one Selection object at a time, but the number of Range objects you can create is unlimited.

The Selection object and the Range object have many common methods and properties, and it is easy to return a Range object from a Selection object or to create a Selection object from a Range object. However, most things you can do with a Selection object, you can do even faster with a Range object. There are two main reasons for this:

  • The Range object typically requires fewer lines of code to accomplish a task.
  • Manipulating a Range object does not incur the overhead associated with Word having to move or change the selection "highlight" in the active document.

In addition, you can do much more with a Range object than you can with a Selection object:

  • You can manipulate a Range object without changing what the user has selected in the document. Practically speaking, you could save the original selection by using a Range object variable, manipulate the Selection object programmatically, then use the saved Range object's Select method to display the original selection. But there is rarely a good reason to show the user that the selection is changing. Some WordBasic developers relied on changing the selection to indicate to the user that the code was still running. But this is not the right way to convey information to a user. An operation that takes a long time to execute should signal its progress by using a progress meter or by posting status messages to the status bar.
  • You can maintain multiple Range objects in your code, and, where necessary, store those objects in a custom Collection object. You cannot do these two things by using only the Selection object.

Working with Bookmarks

In many ways, a Bookmark object is similar to a Selection or Range object in that it represents a contiguous area in a document. It has a starting position and an ending position, and it can be as small as the insertion point or as large as the entire document. However, a Bookmark object differs from a Selection or Range object because you can give the Bookmark object a name and it does not go away when your code stops running or when the document is closed. In addition, although bookmarks are normally hidden, you can make them visible by setting the View object's ShowBookmarks property to True.

You use bookmarks to mark a location in a document or as a container for text in a document. The following examples illustrate these uses:

  • You can use bookmarks to mark areas in a document that will contain data supplied by the user or obtained from an outside source. For example, a business letter template may have bookmarks marking the locations for name and address information. Your Visual Basic for Applications (VBA) code could obtain the data from the user or from a database, then insert it in the locations marked by bookmarks. Once a location is marked, navigating to that location is as simple as navigating to the bookmark. You can determine whether a document contains a specific bookmark by using the Bookmarks collection's Exists method. You display a bookmark location by using the Bookmark object's Select method. Once a bookmark is selected, the Selection object and the Bookmark object represent the same location in the document.
  • If you have a document that contains boilerplate text that you need to modify in certain circumstances, you can use VBA code to insert different text in these specified locations, depending on whether certain conditions are met. You can use a Bookmark object's Range property to create a Range object, then use the Range object's InsertBefore method, InsertAfter method, or Text property to add or modify the text within a bookmark.

Once you understand the subtleties associated with adding or changing text through VBA code, working with bookmarks can be a powerful way to enhance your custom solutions in Word.

You add a bookmark by using the Bookmarks collection's Add method. You specify the bookmark's location by specifying a Range or Selection object in the Add method's Range argument. When you use the InsertBefore method, the InsertAfter method, or the Text property, a Range object automatically expands to incorporate the new text. As you will see in the next few examples, a bookmark does not adjust itself as easily, but making a bookmark as dynamic as a range is a simple exercise.

When you use the Range object's InsertBefore method to add text to a bookmark, the text is added to the start of the bookmark and the bookmark expands to include the new text. For example, if you had a bookmark named CustomerAddress on the following text (the brackets appear when the ShowBookmarks property is set to True):

[Seattle, WA 12345]

you could add the street address to this bookmark by using the following VBA code:

Dim rngRange As Word.Range
Set rngRange = ActiveDocument.Bookmarks("CustomerAddress").Range
rngRange.InsertBefore "1234 Elm Drive #233" & vbCrLf

As you might expect, the bookmark expands to include the additional address information:

[1234 Elm Drive #233
Seattle, WA 12345]

Now suppose you wanted to use the InsertAfter method to add text to the end of a bookmark that contains the street address, and you want to add the city, state, and Zip code information by using this code:

Dim rngRange As Word.Range
Set rngRange = ActiveDocument.Bookmarks("CustomerAddress").Range
rngRange.InsertAfter vbCrLf & "Seattle, WA 12345"

Note that when you use the InsertAfter method to add text to the end of a bookmark, the bookmark does not automatically expand to include the new text:

[1234 Elm Drive #233]
Seattle, WA 12345

This behavior could create problems if you were unaware of it. But now you are aware of it, and the solution is quite easy. The first part of the solution results from the benefits achieved when you use the Selection and Range objects together. The second part results from another aspect of bookmarks that you need to know: When you add a bookmark to a document in which the bookmark already exists, the original bookmark is deleted (but not the text it contained) when the new bookmark is created.

The following sample code uses the InsertAfter method to add text to the end of the CustomerAddress bookmark. It then uses the Range object's Select method to create a Selection object that covers all the text you want to bookmark. Finally, it uses the Bookmarks collection's Add method to add a new bookmark that has the same name as the original bookmark, then uses the Selection object's Range property to specify the location of the bookmark:

Dim rngRange As Word.Range

Set rngRange = ActiveDocument.Bookmarks("CustomerAddress").Range
With rngRange
   .InsertAfter vbCrLf & "Seattle, WA 12345"
   .Select
End With
ActiveDocument.Bookmarks.Add "CustomerAddress", Selection.Range

If you use the Range object's Text property to replace the entire contents of a bookmark, you run into a similar problem: The text in the bookmark is replaced, but in the process, the bookmark itself is deleted. The solution to this problem is the same solution we used for the InsertAfter method in the preceding example. You insert the new text, use the Range object's Select method to select the text, then create a new bookmark that has the same name as the original bookmark.

Where to Get More Info

The techniques discussed in this column should go a long way toward making you more productive when you work with the content of a Word document programmatically. For additional information, check out the following resources:

David Shank is a programmer/writer on the Office team specializing in developer documentation. Rumor has it he lives high in the mountains to the east of Redmond and is one of the few native Northwesterners who still lives in the Northwest.