|
|
The Range object in the Word object model is the primary way to interact with the content of the document. A Range represents a range of contiguous text and provides a way to interact with that range of text, along with any additional elements that are contained in that range of text, such as tables, shapes, lists, and bookmarks. You can get and use as many Range objects as you need in your code. Working with a Range does not change the selection in the document unless you use Range's Select method, which will make the Range you have defined the active selection. If you are interested in working with the active selection, you can use the Selection object, which shares many properties and methods with the Range object. A Range has a start and end that are specified in units of characters in the document and include characters that do not print, such as the carriage returns between paragraphs. A Range whose start and end are the same is sometimes called a collapsed Range and can be thought of as the equivalent of an insertion point at a particular location in the document. Word also has the concept of a story, which is the part of the document that the Range comes from. Most commonly, you work with the main text story, which is the main body of the document. You might also want to get to other text elements in the document, such as headers, footers, comments, footnotes, and endnotes. These other text elements are different stories from the main text story. Getting a RangeYou have several ways to get a Range. We have already considered several document-level collections, such as Sentences, Words, and Characters, that return Range objects. The most common way to get a Range is to use the Range method on the Document object. The Range method takes two optional Object parameters passed by reference: a Start and an End position. You can pass an Integer value to Start and End representing the start and end position of the Range you want to get within the document. If you omit the Start parameter, the parameter defaults to 0, which is the first position in the document. If you omit the End parameter, it defaults to the last position in the document. Listing 8.28 shows an example of getting a Range object using the Document object's Range method. The Range retrieved has a start index of 0 and an end index of 9. As Figure 8.8 shows, the retrieved Range includes nonprinting paragraph marks. Listing 8.28. A VSTO Customization That Works with a Range Object
Figure 8.8. The result of running Listing 8.28: a range of length 9, including nonprinting paragraph characters.
Another way to get a Range is to use the Document object's StoryRanges collection. The StoryRanges collection enables you to get a Range that is not part of the main document, such as a Range within headers, footers, or endnotes. This collection has an index operator that takes a member of the WdStoryType enumeration that specifies what StoryRange you want to access. Listing 8.29 shows some code that iterates over the StoryRanges in the document and displays the type of each StoryRange. Listing 8.29. A VSTO Customization That Iterates over the StoryRanges in the Document
Another way to a get a Range is to get it from the current selection. The Application object's Selection property returns the active selection in the active document as a Selection object. The Selection object has a Range property that returns a Range object that you can work with without affecting the selection (unless you change the Range in some way that forces the selection to reset, such as by replacing the text in the selection). Before getting a Range from a Selection object, verify that the Selection contains a valid Range by checking the Selection object's Type property. The user could have selected a shape in the document, for example, in which case the Range would not be applicable when retrieved from Selection.Range. Listing 8.30 shows an example that checks the Selection.Type property before using Selection.Range. It also checks whether Selection is Nothing, which is a bit of overkill for this example. This case would arise only if no documents are open. Listing 8.30. A VSTO Customization That Gets a Range Object from a Selection Object
Identifying a RangeA Range has several properties to help identify it. The Start and End property return the start and end character index of the Range. The Document property returns the document object the Range is associated with. The StoryType property returns a member of the WdStoryType enumeration identifying the StoryRange with which the Range is associated. The Information property takes a parameter of type WdInformation and returns information as an Object about the Range depending on the enumerated value that is passed to the method. Listing 8.31 shows an example of getting the information associated with a range. If you call the Information property on a Range with an enumerated type that is not applicable, Information will return 1 as a return value. Listing 8.31. A VSTO Customization That Gets Information About a Range
Changing a RangeGiven a Range object, a number of properties and methods enable you to change what a Range refers to. A simple way to modify a Range object is to set the values of the Start and End properties. In addition, you can use several methods to change the Range in other ways. The Expand method expands a Range so that it encompasses the units of the enumeration WdUnits: wdCharacter, wdWord, wdSentence, wdParagraph, wdSection, wdStory, wdCell, wdColumn, wdRow, or wdTable. The Expand method takes a range that only partially covers one of these units and expands it so that the range includes the unit specified. Consider Figure 8.9, for example. For this figure and subsequent figures, we have turned on Word's formatting marks (Tools > Options > View > Formatting Marks > All) so that you can see clearly the spaces and any paragraph marks in the text. The original Range is shown in white text on a black background. The expanded Range after calling Expand with wdWord is shown by the larger border. The original Range contained only e quithe last part of the word The and the first part of the word quick. Calling Expand with wdWord expands the range so that it covers complete words. The expanded Range after calling Expand contains The quick as well as the space after the word quick. Figure 8.9. Result of calling Expand(WdUnits.wdWord) on a Range.
Figure 8.10 shows another example where only three characters of a word are selected. Calling Expand with wdWord expands the Range so that it covers the complete word quick as well as the space after the word quick. Figure 8.10. Result of calling Expand(WdUnits.wdWord) on a Range.
Note that calling Expand repeatedly on a Range passing wdWord does not expand the Range to cover additional words. After a Range no longer contains any partial words, calling Expand with wdWord has no effect. It also follows that a Range that does not start or end with any partial words to start with will not be changed when you call Expand and pass wdWord. This applies to the other members of the WdUnits enumeration. When a Range does not contain any partial sentences, for example, calling Expand with wdSentence has no effect. Figure 8.11 shows an example of calling Expand passing wdSentence. The original Range contains parts of two sentences. The result of calling Expand is that two complete sentences are made part of the Range. Figure 8.11. Result of calling Expand(WdUnits.wdSentence) on a Range.
Figure 8.12 shows another example of calling Expand passing wdSentence. The original Range contains just dog. Expanding the Range adds the rest of the sentence plus the spaces after the sentence. Figure 8.12. Result of calling Expand(WdUnits.wdSentence) on a Range.
The Expand method can change both the start and the end of a Range. The EndOf method works in a similar way to the Expand method but changes only the end of a Range. The EndOf method takes by reference two optional parameters of type Object: Unit and Extend. The Unit parameter can be passed a member of the WdUnits enumeration. The Extend parameter can be passed a member of the WdMovementType enumeration: wdMove or wdExtend. If you pass wdExtend, the EndOf method acts like the Expand method would if it were not allowed to change the start of a Range. Figure 8.13 shows an example of calling EndOf passing wdWord and wdExtend. It expands the Range to cover the partial word at the end of the Range but does not expand to cover the partial word at the beginning of the Range. Figure 8.13. Result of calling EndOf(WdUnits.wdWord, WdMovementType.wdExtend) on a Range.
If you pass wdMove for the second parameter (which is the default if you omit the parameter), EndOf returns a Range whose start and end is equaleffectively returning you an insertion point at the end of the expansion. Figure 8.14 shows a Range that partially covers two words initially. Calling EndOf on this Range and passing wdMove for the second parameter yields a Range whose start and end is 10at the end of the second word. Figure 8.14. Result of calling EndOf(WdUnits.wdWord, WdMovementType.wdMove) on a Range.
The StartOf method works like the EndOf method but changes only the start of the range. The StartOf method takes by reference two optional parameters of type Object: Unit and Extend. The Unit parameter can be passed a member of the WdUnits enumeration. The Extend parameter can be passed a member of the WdMovementType enumeration: wdMove or wdExtend. If you pass wdExtend, the StartOf method acts like the Expand method would if it were not allowed to change the end of a range. Figure 8.15 shows an example of calling StartOf passing wdWord and wdExtend. It expands the Range to cover the partial word at the beginning of the Range but does not expand to cover the partial word at the end of the Range. Figure 8.15. Result of calling StartOf(WdUnits.wdWord, WdMovementType.wdExtend) on a Range.
As with EndOf, the StartOf method when passed wdMove for the second parameter returns a Range whose start and end is equaleffectively returning you an insertion point at the beginning of the expansion. Figure 8.16 shows a Range containing a word at the end of a sentence. Calling StartOf and passing wdSentence and wdMove yields a Range where start and end are 0effectively an insertion point at the beginning of the sentence. Figure 8.16. Result of calling StartOf(WdUnits.wdSentence, WdMovementType.wdMove) on a Range.
Moving a RangeThe Move method can be called repeatedly to move a Range by WdUnits through the document. It does not expand the Range but instead moves the Range, creating a Range whose start and end are equal. The Move method takes by reference optional Unit and Count parameters of type Object. For Unit, you pass the member of the WdUnits enumeration that you want to move by. The default value of Unit is wdCharacter. For Count, you pass a positive or negative Integer specifying how many units you want to move forward or backward. The Move method returns the number of units by which the Range was moved or returns 0 if the Range was not moved. Figure 8.17 shows an example of calling Move passing wdWord and 1. Figure 8.18 shows an example of calling Move passing wdWord and 1. In the first case, the Range moves to the start of the next word. In the latter case, the Range moves to the beginning of the partially selected word. Figure 8.17. Result of calling Move(WdUnits.wdWord, 1) on a Range containing h from The.
Figure 8.18. Result of calling Move(WdUnits.wdWord, -1) on a Range containing h from The.
The Next method works like Move when passed a positive count. Instead of modifying the Range directly, it returns a new Range that would be the result after calling Move. The Previous method works like Move when passed a negative count and also returns a new Range instead of modifying the existing Range. In the case where the Move method would have returned 0 because the Move was not possible, Next and Previous returns Nothing. The MoveUntil method takes a required Object by reference parameter to which you can pass a String containing the characters that you want to find. It takes a second optional Object parameter by reference to which you can pass the number of characters after the Range to search. If MoveUntil cannot find a specified character within the number of characters you pass, it will not change the Range. You can pass a negative number of characters to search the characters before the range. You can also pass to the second optional Object parameter the constant WdConstants.wdForward or WdConstants.wdBackward to specify to search forward or backward without specifying a limit on the number of characters to search. Figure 8.19 shows the result of calling MoveUntil passing "abc" as the String and WdConstants.wdForward for the second parameter. It searches forward until it finds character a, b, or c. The first of those it finds is the c in the word quick. It sets the start and end of the Range to 7. Figure 8.19. Result of calling MoveUntil("abc", WdConstants.wdForward) on a Range containing h from The.
Range has a MoveStart and MoveUntilStart method that work like Move and MoveUntil but affect only the start position of the Range unless the start is moved forward to a position beyond the end, in which case Start and End are set to the same value. Similarly, Range has a MoveEnd and MoveUntilEnd method that work like Move and MoveUntil but affect only the end position of the Range. The SetRange method takes a Start and End parameter as an Integer to set the start and end position of the Range in characters. Using the SetRange is the equivalent of setting the Start and End properties on Range. Ranges and StoriesGiven a Range, you can expand the range to include the full story associated with the Range using the WholeStory method. Some stories are split into multiple linked text elements in a document (text-box stories can be linked, and header and footer stories can be linked), so calling WholeStory cannot give you each of the multiple linked text elements. For these cases, you can use the NextStoryRange property to get the next linked story of the same type. Navigating a RangeEarlier in this chapter you read about the Browser object, which lets you access the same functionality that is available in the browser control shown in Figure 8.1. The Browser object enables you to go easily to the next element of a particular type in a document, such as the next bookmark, comment, or field. The Browser object affects the selection in the document, however, which is often undesirable. To go to the next element of a particular type without affecting the selection, you can use the GoTo method of the Range object. GoTo does not affect the Range object it is called on but instead returns a new Range object that represents the resulting Range after calling GoTo. The GoTo method takes by reference four optional Object parameters. The first parameter, the What parameter, can be passed a member of the WdGoToItem enumeration:
The second parameter, the Which parameter, can be passed a member of the WdGoToDirection enumeration: wdGoToAbsolute, wdGoToFirst, wdGoToLast, wdGoToNext, wdGoToPrevious, or wdGoToRelative. The wdGoToAbsolute value can be used to go to the nth item of the type specified by the What parameter. The third parameter, the Count parameter, is passed the number of the item to get and is affected by the second parameter. If What is passed wdGoToLine and Count is passed 1, for example, depending on the Which parameter, GoTo could go to the next line after the Range (wdGoToNext), the first line in the document (wdGoToAbsolute), or the line previous to the current Range (wdGoToPrevious). The fourth parameter, the Name parameter, can be passed a name if the What argument specifies an element identifiable by name: wdGoToBookmark, wdGoToComment, or wdGoToField. GoToNext and GoToPrevious are simpler versions of the GoTo method that take only the What parameter and go to the next or previous instance of the type of object specified by the What parameter. Listing 8.32 shows an example of using the GoTo method on a Range to navigate the pages in a document and display the first sentence on each page. We also use Information to get the page count and Expand to expand the collapsed Range returned by GoTo to include the first sentence on the page. Listing 8.32. A VSTO Customization That Uses the GoTo Method
Collapsing a RangeWe have already mentioned several times the concept of a collapsed Rangea Range whose start and end is equal. The Collapse method takes a Range and collapses it. It takes by reference an optional parameter Direction of type Object. You can pass a member of the WdCollapseDirection enumeration: wdCollapseEnd, which makes Start equal to End, or wdCollapseStart, which makes End equal to Start. If you omit the Direction parameter, the default is wdCollapseStart. Getting Text from a RangeThe Text property returns a String containing the text in the Range. The behavior of the Text property can be changed by using the TextRetrievalMode property, which returns a TextRetrievalMode object. Setting the TextRetrievalMode object's IncludeFieldCodes property to TRue makes it so the Text property returns field codes. The default is the setting of the Field Codes check box in the View tab of the Options dialog box. Setting the TextRetrievalMode object's IncludeHiddenText property to true makes it so the Text property returns hidden text in the document. The default is the setting of the Hidden Text check box in the View tab of the Options dialog box. The TextRetrievalMode object's ViewType property can also affect what the Text property returns. The ViewType property can be set to a member of the WdViewType enumeration: wdMasterView, wdNormalView, wdOutlineView, wdPrintPreview, wdPrintView, wdReadingView, or wdWebView. When set to wdOutlineView, for example, Text returns only the text visible in outline view. Listing 8.33 shows the creation of some text in a document that includes a field and some hidden text. Then the Text property is used in several ways, showing the effect of changing TextRetrievalMode settings. Listing 8.33. A VSTO Customization That Modifies TextRetrievalMode Settings
Setting the Text in a RangeSetting the Text property to a string value is the most basic way to set text in a Range. Setting the Text property replaces the text in the Range with the string value and changes the end of the Range so the start and end cover the length of the new string. If the Range is collapsed, setting the Text property does not replace any existing text, but it inserts the new string at the location of the Range and changes the end of the Range so that the start and end cover the length of the new string. Setting the Text property only changes the characters of the Range, not the formatting. If you have one Range formatted a particular way and a second Range you want to copy both the text of the first Range and its formatting to, you can use the FormattedText property, which takes a Range. Listing 8.34 shows an example of using the FormattedText property to take one Range that is formatted and to set the text and formatting of a second Range to the first. Listing 8.34. A VSTO Customization That Uses FormattedText to Set Text and Formatting
Each time you set the Text property, it replaces the existing Range and changes the end of the Range so that the start and end cover the new string. The InsertAfter method lets you add text immediately after the Range without replacing the existing Range. The InsertAfter method takes a String for the text you want to insert after the Range. InsertAfter changes the end of the Range so that the start and end cover the old Range and the string you have added after the Range. The InsertBefore method lets you add text immediately before the Range without replacing the existing Range. The InsertBefore method takes a String for the text you want to insert before the Range. InsertBefore changes the end of the Range so that the start and end cover the old Range and the string you have added before the Range. Inserting Nonprinting Characters and BreaksYou have several ways to insert nonprinting characters, such as tabs and paragraph marks. A simple way is to use constants provided for you by Visual Basic 2005. In a string, you can specify a tab with the constant vbTab. You can specify a paragraph mark (a new line) by using vbCrLf. Listing 8.35 shows some examples of using these constants to insert nonprinting characters. Figure 8.20 shows the result of running Listing 8.35 with nonprinting characters showing. Listing 8.35. A VSTO Customization That Uses Visual Basic Constants and the Text Property
Figure 8.20. Result of running Listing 8.35.
It is also possible to insert paragraphs using the InsertParagraph method. The InsertParagraph method inserts a new paragraph at the start position of the Range, replacing the current Range. It changes the Range so that it covers the start position and the newly inserted paragraph mark. InsertParagraph is the equivalent of setting the Text property to vbCrLf. InsertParagraphBefore inserts a new paragraph at the start position of the Range and changes the end of the Range to expand it to cover the old Range and the newly inserted paragraph mark. InsertParagraphBefore is the equivalent of calling the InsertBefore method and passing vbCrLf. InsertParagraphAfter is the equivalent of calling the InsertAfter method and passing vbCrLf. Figure 8.21 shows some additional kinds of breaks that a user can insert into a document using the Break command from the Insert menu. These types of breaks can be inserted programmatically using Range's InsertBreak method. The InsertBreak method takes by reference an optional parameter of type Object to which you can pass a member of the WdBreakType enumeration. The members of the WdBreakType enumeration correspond to the breaks in Figure 8.21: wdPageBreak, wdColumnBreak, wdTextWrappingBreak, wdSectionBreakNextPage, wdSectionBreakContinuous, wdSectionBreakEvenPage, and wdSectionBreakOddPage. InsertBreak works like setting the Text property would; the current Range is replaced with the break, or if the Range is collapsed, the break is inserted at the position of the Range. Figure 8.21. The Break dialog box.
Working with FormattingThe Font property returns a Font object that controls font settings for the Range. Many of the properties associated with Font, such as the Bold property, that you would expect to be of type Boolean are instead of type Integer. This is because a particular Range could be all bold, partially bold, or not bold, for example. If the Range is partially bold, it returns WdConstants.wdUndefined. If the Range is not bold, it returns a 0. If the Range is all bold, it returns a 1. This is another example where the COM implementation of the Word object model peeks through, because 1 corresponds to a true value in COM object models. This can cause confusion, because the Boolean value for TRue in .NET when cast to an integer is 1, not 1. So when checking the value of these properties, remember to not make the mistake of comparing to 1 or the Boolean value of true cast to an Integer because this will cause your code to fail to detect the state properly. Instead, always compare to 0 or the Boolean value of False cast to an Integer. Table 8.14 lists several of the most frequently used properties associated with the Font object.
Another way to set the formatting of a Range is to use the Style property. The Style property takes by reference an Object parameter. You can pass a String representing the name of the style you want to use to format the Range. Listing 8.36 shows some formatting of a Range using Font properties and the Style property. Figure 8.22 shows the document created by Listing 8.36. Listing 8.36. A VSTO Customization That Formats a Range
Figure 8.22. Result of running Listing 8.36.
Find and ReplaceThe Find property returns a Find object that you can use to search a Range. The Find object allows you to set options similar to the ones you find in Word's Find dialog box. The Find object's Text property can be set to the String you want to search for. The Find object's MatchWholeWord property can be set to False to allow matching of the string against a partial word in the Range. After the find options have been set up, the Find object's Execute method executes the find against the Range. Execute takes a number of optional parameters by referencesome of which correspond to properties on the Find object. So, you have an option of either presetting Find properties and then calling Execute and omitting the optional parameters, or skipping presetting Find properties and passing optional parameters to the Execute method. In Listing 8.36, we take the former approach. Execute returns TRue if it is able to find the text specified and modifies the Range so that it covers the found text. In Listing 8.37, calling Execute modifies the Range to have a start of 20 and an end of 24. Listing 8.37. A VSTO Customization That Uses the Find Object
It is also possible to iterate over multiple found items using the Find object's Found property instead of checking the return value of Execute each time. Listing 8.38 shows an example of iterating over every occurrence of the string "jump" in a document. This example bolds every instance of jump that it finds in the document. Listing 8.38. A VSTO Customization That Uses the Find Object's Found Property to Iterate over Found Items
The Find object has a Replacement property that returns a Replacement object, which allows you to set options for doing a find and replace. The Replacement object's Text property lets you set the text you want to use to replace found text with. In addition, to perform a replacement, you must pass a member of the WdReplace enumeration to the Replace parameter of the Execute method (the 11th optional parameter). You can pass wdReplaceAll to replace all found occurrences or wdReplaceOne to replace the first found occurrence. In Listing 8.39, we use the Replacement.Text property to set the replace string and then call Execute passing wdReplaceAll to the Replace parameter. Listing 8.39. A VSTO Customization That Performs a Replace
|
|
|