Visual Studio Tools for Office: Using Visual Basic 2005 with Excel, Word, Outlook, and InfoPath

The Document object represents an open document in Word. The Document object has a Name property that returns a String representing the name of the document (for example, "doc1.doc"). If the document has not yet been saved, this property returns the temporary name of the documenttypically, something like Document1.

Document also has a FullName property that returns a String representing the full filename of the document if the document has been saved. Once again, if the document has not been saved, this property returns the temporary name of the document, such as Document1. The FullName of the document can be passed to the Item property of the Documents collection to access the document by name from that collection. The Path property returns a String representing the path to the folder where the document is stored. A document with FullName "c:\mydocuments\doc1.doc" returns "c:\mydocuments" for the Path property, for example. If the document has not yet been saved, the Path returns an empty string.

The Type property is of type WdDocumentType and can be used to determine whether the document is a Word document or a Word template file. A Word document returns the enumerated value wdTypeDocument. A template returns the value wdTypeTemplate.

Preserving the Dirty State of a Document

Saved is a Boolean property that tells you whether a document needs to be saved. A document that has not been changed, such as a new document that has not been typed in yet or a document that has been opened but not edited, returns TRue for Saved. A document that has been changed returns False until the user or code saves the document and thereby resets the Saved property to true. A document that has been changed but not saved is often referred to as a dirty document.

You can also set the value of the Saved property so that a change made by your code does not dirty the document. You might make a change through code to a document, for example, but you do not want to save the change made by your code unless the user makes some additional change to the document. This is often desirable because when users open a document and do not edit it, they are confused when they are prompted to save because code associated with the document changed the state of the document in some way. You can get the value of the Saved property, make the change to the document, and then set the value of Saved back, as shown in Listing 8.21.

Listing 8.21. A VSTO Customization That Preserves the Dirty State of the Document by Using the Saved Property

Public Class ThisDocument Private Sub ThisDocument_Startup(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Startup Dim oldSaved As Boolean = Me.Saved Try Dim props As Office.DocumentProperties = _ Me.CustomDocumentProperties Dim prop As Office.DocumentProperty = props.Add( _ "My Property", False, _ Office.MsoDocProperties.msoPropertyTypeString, _ "My Value") Finally Me.Saved = oldSaved End Try End Sub End Class

Closing and Saving a Document

The Close method enables you to close a document. The Close method takes three optional Object parameters passed by reference. 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. The second parameter controls Word's behavior when saving a changed document whose original format was not Word document format. This parameter can be passed wdOriginalDocumentFormat, wdPromptUser, or wdWordDocument. 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.

The Save method saves the document and does the same thing that choosing Save from the File menu would do. If the document has already been saved, it saves the document to the location it was last saved to. If the document has not yet been saved, it brings up the Save As dialog box so that the user can select a place to save the document.

The SaveAs method takes 16 optional Object parameters passed by reference. It gives you full control over the filename to save to, as well as the file format and several other options. Table 8.7 lists the optional parameters of type Object that are passed by reference to the SaveAs method.

Table 8.7. Optional Parameters for the Document Object's SaveAs Method

Parameter Name

What It Does

FileName

Pass a String representing the filename to use for the document. The default is the current FullName of the document.

FileFormat

Pass a member of the WdSaveFormat enumeration to specify the file format to save as.

LockComments

Pass TRue to lock the document for comments. The default is False.

Password

Pass the password for opening the document as a String.

AddToRecentFiles

Pass true to add the filename to the list of recently used files in the File menu. The default is true.

WritePassword

Pass the password for saving changes to the document as a String.

ReadOnlyRecommended

Pass true to have Word always suggest that the document be opened as read-only. The default is False.

EmbedTrueTypeFonts

Pass true to save TrueType fonts in the document. If omitted, Word will use the value of Document.EmbedTrueTypeFonts.

SaveNativePictureFormat

Pass true to save pictures imported from the Mac in their Windows version.

SaveFormsData

Pass true to save the data entered by the user entered in a form as a data record.

SaveAsAOCELetter

Pass true to save the document as an AOCE letter if the document has an attached mailer.

Encoding

Pass a member of the Office.MsoEncoding enumeration specifying the code page or character set to be used when you save the document.

InsertLineBreaks

If the document is saved in a text format (for example, you passed WdSaveFormat.wdFormatText to the FileFormat parameter), pass TRue to insert line breaks at the end of each line of text.

AllowSubstitutions

If the document is saved in a text format, pass TRue to convert some symbols with text that looks similar. Replace the symbol © with (c), for example.

LineEnding

If the document is saved in a text format, pass a member of the WdLineEndingType enumeration to specify the way Word marks line and paragraph breaks.

AddBiDiMarks

If you pass true, Word adds control characters to the file to preserve the bidirectional layout of the document.

Working with Windows Associated with a Document

A particular document can have one or more windows associated with it. Even when a document is opened with False passed to the Visible parameter of the Documents collection's Open method, it still has a window associated with it, albeit a window whose Visible property is False. When a document has multiple windows associated with it, you can use the Windows property to return the collection of windows associated with that document. You can determine which of the windows will have the focus when the document is active by using the ActiveWindow property. To activate a particular document and make its ActiveWindow the one with focus, use the Activate method.

Changing the Template Attached to a Document

A document always has a template associated with it. By default, the template is the Normal template (normal.dot), also available from the Application object's NormalTemplate property. A document might be associated with some other template, usually because it was created from a particular template.

If you have a Document object and you want to determine what template is associated with it, you can use the AttachedTemplate property. When you get the value of AttachedTemplate, it returns an Object that you can cast to a Template object. When you set the value of AttachedTemplate, you can pass either a Template object or a String containing the filename of the template.

Important Collections Associated with Both Document and Range

The Document and Range objects share a number of properties that return collections you will frequently use. Rather than consider these properties both in this section and in the section on Range later in this chapter, we cover both of them here only. Table 8.8 shows these properties associated with both Range and Document that return important collection objects.

Table 8.8. Properties Associated with Both Document and Range That Return Important Collections

Property Name

Type

What It Does

Bookmarks

Bookmarks

Returns the Bookmarks collection. Bookmarks can be used to mark certain areas of a document and then return easily to those areas of the document. Bookmarks are discussed in more detail in the section "Working with Bookmarks" later in this chapter.

Characters

Characters

Returns the Characters collection, which enables you to work with a Document or Range at the level of an individual character. The Characters collection returns one-character-long Range objects.

Comments

Comments

Returns the Comments collection, which enables you to access comments made by reviewers in the Document or Range.

Endnotes

Endnotes

Returns the Endnotes collection, which enables you to access the endnotes associated with a Document or Range.

Fields

Fields

Returns the Fields collection, which enables you to access the fields used in a Document or Range.

Footnotes

Footnotes

Returns the Footnotes collection, which enables you to access the footnotes used in a Document or Range.

Hyperlinks

Hyperlinks

Returns the Hyperlinks collection, which enables you to access hyperlinks in a Document or Range.

InlineShapes

InlineShapes

Returns the InlineShapes collection, which enables you to access an InlineShape (an InlineShape can include a drawing, an ActiveX control, and many other types of objects enumerated in the Office.MsoShapeType enumeration) that has been inserted inline with the text in a Document or Range.

Paragraphs

Paragraphs

Returns the Paragraphs collection, which enables you to access individual Paragraph objects associated with the Document or Range.

Revisions

Revisions

Returns the Revisions collection, which enables you to access a Revision made in the Document or Range.

Sections

Sections

Returns the Sections collection, which enables you to access a Section within the Document or Range. A new Section can be added using the Break command from the Insert menu.

Sentences

Sentences

Returns the Sentences collection, which enables you to work with a Document or Range at the level of an individual sentence. The Sentences collection returns a Range object for each sentence.

Tables

Tables

Returns the Tables collection, which enables you to access a Table within the Document or Range.

Words

Words

Returns the Words collection, which enables you to work with a Document or Range at the level of an individual word. The Words collection returns a Range object for each word.

Note that the Characters, Sentences, and Words collections are special collections that return Range objects when you iterate over them. Listing 8.22 shows a VSTO customization that uses these collections, as well as the Paragraphs collection. It creates a document with some text in it and then a second document to output information about the first document.

Listing 8.22. A VSTO Customization That Uses the Characters, Paragraphs, Sentences, and Words Collections

Public Class ThisDocument Private Sub ThisDocument_Startup(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Startup Dim r As Word.Range = Me.Range() r.Text = "Whether I shall turn out to be the hero " & _ "of my own life, or whether that station will be " & _ "held by anybody else, these pages must show. To " & _ "begin my life with the beginning of my life, I " & _ "record that I was born (as I have been informed " & _ "and believe) on a Friday, at twelve o'clock at " & _ "night. It was remarked that the clock began " & _ "to strike, and I began to cry, simultaneously." Dim reportDoc As Word.Document reportDoc = Me.Application.Documents.Add() Dim report As Word.Range = reportDoc.Range report.InsertAfter( _ String.Format("There are {0} paragraphs." & _ vbCrLf, _ Me.Paragraphs.Count)) For Each paragraph As Word.Paragraph In Me.Paragraphs report.InsertAfter(String.Format("{0}\" & vbCrLf, _ paragraph.Range.Text)) Next report.InsertAfter(String.Format( _ "There are {0} sentences." & _ vbCrLf, Me.Sentences.Count)) For Each sentence As Word.Range In Me.Sentences report.InsertAfter(String.Format( _ "{0}" & vbCrLf, sentence.Text)) Next report.InsertAfter(String.Format( _ "There are {0} words." & vbCrLf, _ Me.Words.Count)) For Each word As Word.Range In Me.Words report.InsertAfter(String.Format( _ "{0}" & vbCrLf, word.Text)) Next report.InsertAfter(String.Format( _ "There are {0} characters." & _ vbCrLf, Me.Characters.Count)) For Each character As Word.Range In Me.Characters report.InsertAfter(String.Format( _ "{0}" & vbCrLf, character.Text)) Next End Sub End Class

Important Collections Associated with Document Only

Some properties return collections associated only with Document, not with Range. Table 8.9 shows several of these properties.

Table 8.9. Properties Associated with Document That Return Important Collections

Property Name

Type

What It Does

CommandBars

CommandBars

Returns the CommandBars collection. The CommandBars collection is used to add new toolbars, buttons, and menus to Word.

Shapes

Shapes

Returns the Shapes collection. The Shapes collection contains Shape objects (a Shape can include a drawing, an ActiveX control, and many other types of objects enumerated in the Office.MsoShapeType enumeration) that are not inline with text but are free floating in the document.

StoryRanges

StoryRanges

Returns the StoryRanges collection. The StoryRanges collection provides a way to access ranges of text that are not part of the main body of the document, including headers, footers, footnotes, and so on. The StoryRanges collection's Item property is passed a member of the enumeration WdStoryType.

Versions

Versions

Returns information about the different versions of the document if the document is being checked in and out of a workspace.

Working with Document Properties

Document has a BuiltinDocumentProperties property that returns an Object that can be cast using CType to an Office.DocumentProperties collection representing the built-in document properties associated with the document. These are the properties that you see when you choose Properties from the File menu and click the Summary tab. These include properties such as Title, Subject, Author, and Company. Table 8.10 shows the names of all the document properties associated with a document.

Table 8.10. The Names of the Built-In Document Properties in Word

Application Name

Last print date

Number of pages

Author

Last save time

Number of paragraphs

Category

Manager

Number of slides

Comments

Number of bytes

Number of words

Company

Number of characters

Revision number

Creation date

Number of characters (with spaces)

Security

Format

Number of hidden slides

Subject

Hyperlink base

Number of lines

Template

Keywords

Number of multimedia clips

Title

Last author

Number of notes

Total editing time

Document also has a CustomDocumentProperties property that returns an Object that can be cast to an Office.DocumentProperties collection representing any custom document properties associated with the document. These are the custom properties that you see when you choose Properties from the File menu and click the Custom tab. Custom properties can be created by your code and used to store name-and-value pairs in the document.

The DocumentProperties collection and DocumentProperty object are located in the Microsoft Office 11.0 Object Library (office.dll), which contains objects shared by all the Office applications. These objects are in the Microsoft.Office.Core namespace and typically are brought into Office projects in an Office namespace as shown here:

Imports Office = Microsoft.Office.Core

Listing 8.23 shows an example of iterating over the DocumentProperties collection returned by the CustomDocumentProperties and BuiltInDocumentProperties properties. We get the value of the built-in properties in a try/Catch block because some built-in properties throw exceptions when their values are accessed.

Listing 8.23. A VSTO Customization That Iterates over DocumentProperties Collections

Public Class ThisDocument Private Sub ThisDocument_Startup(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Startup Dim cProps As Office.DocumentProperties = _ Me.CustomDocumentProperties Dim bProps As Office.DocumentProperties = _ Me.BuiltInDocumentProperties Dim doc As Word.Document = Me.Application.Documents.Add() Dim range As Word.Range = doc.Range range.InsertAfter( _ "Built-in Document Properties" & vbCrLf & vbCrLf) For Each bProp As Office.DocumentProperty In bProps Dim name As String = bProp.Name Dim value As Object = Nothing Try value = bProp.Value Catch ex As Exception value = ex.Message End Try range.InsertAfter(String.Format("{0} - {1}" & _ vbCrLf, name, value)) Next range.InsertAfter( _ "Custom Document Properties" & vbCrLf & vbCrLf) For Each cProp As Office.DocumentProperty In cProps range.InsertAfter(String.Format("{0} - {1}" & _ vbCrLf, cProp.Name, cProp.Value)) Next End Sub End Class

To access a DocumentProperty in a DocumentProperties collection, you use the indexing syntax (docProperties(Object)), which returns a DocumentProperty object. The indexer takes an Index parameter of type Object. You can pass an Integer representing the 1-based index of the DocumentProperty in the collection you want to access. Alternatively, you can pass a String representing the name of the DocumentProperty you want to access. As with other collections, the Count property returns how many DocumentProperty objects are in the collection.

A DocumentProperty object has a Name property that returns a String containing the name of the property. It also has a Value property of type Object that returns the value of the property. You can check what the type is of Value by using the Type property that returns a member of the Office.MsoDocProperties enumeration: msoPropertyTypeBoolean, msoPropertyTypeDate, msoPropertyTypeFloat, msoPropertyTypeNumber, or msoPropertyTypeString.

Listing 8.24 shows how a DocumentProperty is accessed.

Listing 8.24. A VSTO Customization That Accesses a DocumentProperty Using an Indexer

Public Class ThisDocument Private Sub ThisDocument_Startup(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Startup Dim bProps As Office.DocumentProperties = _ Me.BuiltInDocumentProperties Dim author As Office.DocumentProperty = bProps("Author") MessageBox.Show(String.Format( _ "Property {0} is set to {1}.", _ author.Name, author.Value)) Dim third As Office.DocumentProperty = bProps(3) MessageBox.Show(String.Format( _ "Property {0} is set to {1}.", _ third.Name, third.Value)) End Sub End Class

You can add a custom DocumentProperty to a DocumentProperties collection by using the Add method. The Add method takes the parameters shown in Table 8.11.

Table 8.11. The DocumentProperties Collection's Add Method Parameters

Parameter Name

Type

What It Does

Name

String

Sets the name of the new property.

LinkToContent

Boolean

Sets whether the property is linked to the contents of the container document.

Type

optional Object

Sets the data type of the property. Can be one of the following Office.MsoDocProperties enumerated values: msoPropertyTypeBoolean, msoPropertyTypeDate, msoPropertyTypeFloat, msoPropertyTypeNumber, or msoPropertyTypeString.

Value

optional Object

Sets the value of the property if LinkToContent is False.

LinkSource

optional Object

Sets the source of the linked property if LinkToContent is TRue.

Listing 8.25 shows an example of adding a custom DocumentProperty of type msoPropertyTypeString. Note that Word will let you set the value to a long String, but it will truncate that value to 255 characters. Fortunately, VSTO enables developers to store larger amounts of data in a document through a feature called cached data. For more information on the cached-data feature of VSTO, see Chapter 18, "Server Data Scenarios."

Listing 8.25. A VSTO Customization That Adds a Custom DocumentProperty

Public Class ThisDocument Private Sub ThisDocument_Startup(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Startup Dim props As Office.DocumentProperties props = Me.CustomDocumentProperties Dim prop As Office.DocumentProperty Prop = props.Add("My Property", _ False, Office.MsoDocProperties.msoPropertyTypeString, _ "My Value") MsgBox(String.Format("Property {0} is set to {1}.", _ prop.Name, prop.Value)) End Sub End Class

Checking Spelling and Grammar in Documents and Ranges

You can control the grammar checking in a Document or Range by using the following methods and properties. GrammarChecked is a Boolean property that returns TRue if the grammar in the document or range has been checked. If the grammar has not yet been checked, you can force a grammar check by calling the CheckGrammar method. You can control whether Word shows the grammatical errors in the document by setting the ShowGrammaticalErrors property to TRue or False. The GrammaticalErrors property returns a ProofreadingErrors collection, which is a collection of Range objects containing the ranges of grammatically incorrect text.

A similar set of methods and properties exists for checking spelling. SpellingChecked is a Boolean property that returns true if the spelling in the document or range has been checked. If the spelling has not yet been checked, you can force a spelling check by calling the CheckSpelling method. The CheckSpelling takes 12 optional Object parameters passed by reference that you can omit unless you want to specify additional custom dictionaries to check the spelling against.

You can control whether Word shows the spelling errors in the document by setting the ShowSpellingErrors property to true or False. The SpellingErrors property returns a ProofreadingErrors collection, which is a collection of Range objects containing the ranges of incorrectly spelled text.

Listing 8.26 shows an example that uses many of these properties and methods.

Listing 8.26. A VSTO Customization That Checks Grammar and Spelling

Public Class ThisDocument Private Sub ThisDocument_Startup(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Startup Me.Range.Text = "This are a test of the emegency " & _ "broadcastin system." If Not Me.GrammarChecked Then Me.CheckGrammar() End If If Not Me.SpellingChecked Then Me.CheckSpelling() End If Me.ShowGrammaticalErrors = True Me.ShowSpellingErrors = True For Each range1 As Word.Range In Me.GrammaticalErrors MsgBox(String.Format( _ "Grammatical error: {0}", range1.Text)) Next For Each range2 As Word.Range In Me.SpellingErrors MsgBox(String.Format( _ "Spelling error: {0}", range2.Text)) Next End Sub End Class

Printing a Document

The Document object has a PageSetup property that returns a PageSetup object that has several properties for configuring the printing of a document. The PrintOut method can be used to print a document. It has 18 optional Object parameters passed by reference. Table 8.12 lists some of the most commonly used optional parameters for PrintOut.

Table 8.12. Some of the Optional Parameters for PrintOut

Parameter Name

What It Does

Background

Pass TRue to have PrintOut return immediately and let the code continue while Word prints in the background.

Range

Pass a member of the WdPrintOutRange enumeration: wdPrintAllDocument, wdPrintCurrentPage, wdPrintFromTo, wdPrintRangeOfPages, or wdPrintSelection.

OutputFileName

Pass the full filename of the file you want to print to when PrintToFile is passed TRue.

From

Pass the starting page number to print from when Range is set to wdPrintFromTo.

To

Pass the ending page number to print to when Range is set to wdPrintFromTo.

Copies

Pass the number of copies to print.

Pages

When Range is set to wdPrintRangeOfPages, pass a String representing the page numbers and page ranges to print (for example, "1-5, 15").

PageType

Pass a member of the WdPrintOutPages enumeration: wdPrintAllPages, wdPrintEvenPagesOnly, or wdPrintOddPagesOnly.

PrintToFile

Pass true to print to a file. Used in conjunction with the OutputFileName parameter.

Collate

Pass true to collate.

Listing 8.27 shows a simple example that sets some page-margin options using the PageSetup property and then calls PrintOut specifying that two copies be printed.

Listing 8.27. A VSTO Customization That Uses the PrintOut Method

Public Class ThisDocument Private Sub ThisDocument_Startup(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Startup Me.Range.Text = "This is a test of printing." ' Margins are specified in points. PageSetup.LeftMargin = 72.0F PageSetup.RightMargin = 72.0F Me.PrintOut(Copies:=2) End Sub End Class

Working with Document Protection

Document protection enables you to protect a Word document so the document can be edited only in certain ways by certain people. Document protection in Word works on the principle of exclusions; you first protect the whole document as read-only and then mark certain areas of the document as exclusions. This allows your users to edit only the parts of the document that you specify as exclusions.

Figure 8.4 shows the Protect Document task pane that is shown when you choose Protect Document from the Tools menu. The Allow Only This Type of Editing in the Document check box has been checked, and the drop-down list has been set to not allow any changes. You can optionally allow users to make comments in the document, fill out forms, or make tracked changes to the document.

Figure 8.4. The Protect Document task pane.

Given a basic protection level for the document, you can then add some exceptions by selecting the parts of the document that should be editable and checking either a Groups or Individuals check box to allow that group or individual to edit the selection. Word always provides an Everyone group, but you can add groups and individuals by clicking the More Users link in the task pane. Clicking this link brings up a dialog box that lets you enter a Windows username (DOMAIN\username), Windows user group (DOMAIN\usergroup), or e-mail address.

After you have selected the parts of the document you want to be exceptions and checked the check box next to the groups or individuals you want to be able to edit those parts of the document, click the Yes, Start Enforcing Protection button to protect the document to bring up the Start Enforcing Protection dialog box, shown in Figure 8.5. Word prompts you for an optional password if you want to require a password to remove the document protection. Word can also use user authentication to protect and encrypt the document to protect it further.

Figure 8.5. The Start Enforcing Protection dialog box.

With protection enforced, Word highlights the area of the document that you are allowed to edit based on the exception set for the document. Figure 8.6 shows a document that has been protected but has the first sentence as an editing exception for the Everyone group. Word highlights the regions that you are allowed to edit in the document and provides a task pane for navigating between regions you are allowed to edit.

Figure 8.6. A document with protection enforced but with an exception to allow editing of the first sentence.

Document-protection settings apply to code that is talking to the Word object model, too. If the user is not allowed to edit any sentence but the first sentence, code is also restricted to being able to change only the first sentence. If you run code that tries to change protected parts of the document, an exception is raised.

Word provides several properties and methods that enable you to protect the document programmatically and examine protection settings, as listed in Table 8.13.

Table 8.13. Properties and Methods Used with Document Protection

Name

Type

What It Does

ProtectionType

WdProtectionType

Returns the protection type for the document: wdAllowOnlyComments, wdAllowOnlyFormFields, wdAllowOnlyReading, wdAllowOnlyRevisions, or wdNoProtection.

Permission

Permission

The Permission object lets you work with IRM (Information Rights Management) permissions. This type of protection via IRM permissions is more secure than simple document protection because it involves more validation of identity and encryption of the document.

Protect(...)

 

The Protect method lets you apply protection programmatically.

Unprotect(...)

 

The Unprotect method lets you remove protection programmatically.

Range.Editors

Editors

Given a Range that is an exclusion, Range.Editors will return an Editors collection, which lets you inspect the groups and individuals allowed to edit that Range.

Working with Password Protection

In addition to a password that may be associated with document protection, a Word document can have a password that must be entered to open the document. It can also have a second password associated with it that must be entered to modify or write to the document. These passwords can be set by choosing the Tools menu in the Save As dialog box and picking Security Options. Figure 8.7 shows the Security dialog box.

Figure 8.7. The Security dialog box.

The Document object's HasPassword property returns TRue if the document has been protected with a password that must be entered to open the document. The Password property is a write-only property that can be set to a String value representing the password for the document. Word also has the notion of a password to allow the user to modify or write to the document. If the WriteReserved property returns true, the document has been protected with a password that must be entered to modify or write to the document. The WritePassword property is a write-only property that can be set to a String value representing the write and modify password for the document.

Undo and Redo

Unlike Excel, Word adds the changes you make with your code to the undo stack. You can undo and redo actions your code or a user has taken using the Document object's Undo and Redo methods. Both methods take by reference an optional object parameter that you can set to the number of undo steps or redo steps you want to take. The UndoClear method clears the undo stack, making it so the user can neither undo nor redo any recent actions.

Категории