Restarting list numbering using VBA
Article contributed by Margaret Aldis
with code from John McGhie and Steve Hudson
This article provides details of how to restart list numbering by using VBA code to manipulate the list format, and discusses the workarounds needed to cope with the inherent problems of this method (and of the Restart Numbering command method). For other methods of restarting list numbering, see How to restart style-based numbering.
Using this macro code to apply the restart marker is the equivalent of using the Restart Numbering command, which was not available before Word 2002.
Macros to restart numbering
The following macro will restart list numbering on the first item of a selected list:
Public Sub RestartListNumbering(Optional Scope As Range)
'(c) 1999-2004 Word Heretic steve@wordheretic.com
' Everyone has permission to redistribute and use this code at will,
' providing the (c) notice is left intact.
'Restarts list numbering, 97-XP, all list implementations
Dim KillScope As Boolean
If Scope Is Nothing Then
Set Scope = Selection.Range
KillScope = True
End If
'Use first listpara
With Scope.ListParagraphs
If .Count > 0 Then
With .Item(1).Range.ListFormat
.ApplyListTemplate .ListTemplate, False
End With
End If
End With
'Destroy our objects
If KillScope Then Set Scope = Nothing
End Sub
This method can be used in combination with applying numbering using styles. For example, the following code formats the selected paragraphs as a complete list, including applying the restart to the first item and special spacing for the final item.
Sub ListNumber()
' Macro created by John McGhie from an idea by Steve Hudson
With Selection.Paragraphs
.Style = "List Number"
With .First.Range.ListFormat
.ApplyListTemplate .ListTemplate, False
End With
With .Last
.KeepWithNext = False
.SpaceAfter = 10
End With
End With
End Sub
Note that the code steers clear of the ListGalleries collection and works directly with the current ListTemplate, thus avoiding any unwanted changes to styles and list template linking. However, like the built-in RestartNumbering command available from the user interface, it still applies the numbering as direct formatting, and creates a 'restart marker'.
For more information on the Word object model for list formatting, see the Word VBA Help for the List, ListFormat and ListTemplate objects.
Problems and workarounds
There are two basic problems with applying a restart using the code above or the Restart Numbering command:
- The list formatting is no longer directly determined by the style. If you reset paragraphs to style in order to tidy up formatting, your restarts will be lost. For the same reason, if you update the style you might find that the paragraphs that have been restarted don't update their numbering format to match.
- The restart marker can be lost or moved on copy and paste. Unless you are working in Word 2003 with the document protected for styles, when you paste earlier in the same document the restart marker moves with the pasted text, leaving the original list you copied from continuing from whatever previous list Word finds. If you paste into a different document, you will probably find that the pasted lists do not restart where you expect.
Steve Hudson has produced a number of macros to address these and other problems - in particular his RestartListsAfterHeadings macro solves the problem of lost restarts by recreating them based on the document outline structure. Another strategy would be to mark the restarted paragraphs in some way, so that after they are reset to style or pasted the restarts can be reinstated. The following code illustrates a possible approach to this.
The first macro finds all items numbered 1 for the List Number style and marks them with a temporary bookmark. This code could be run before copying text containing lists to the clipboard, and before any change to the style. If the paste is to be to a different document, similar code would need to be run there (using a distinct bookmark sequence).
Public Sub MarkRestarts()
' Sample code to mark restarted List Number paragraphs
Dim ListItem As Paragraph
Dim n As Integer ' bookmark id
n = 1
For Each ListItem In ActiveDocument.ListParagraphs
If ListItem.Style = _
ActiveDocument.Styles(wdStyleListNumber).NameLocal Then
If ListItem.Range.ListFormat.ListValue = 1 Then
ActiveDocument.Bookmarks.Add "restart" & n, _ ListItem.Range
n = n + 1
End If
End If
Next ListItem
End Sub
Even if the source list loses its restart, it will retain the bookmark, which allows the restart to be reapplied as follows:
Public Sub ReapplyRestarts()
' Sample macro to reapply restarts lost by a copy and paste
Dim aBookmark As Bookmark
Dim RestartPoint As Range
For Each aBookmark In ActiveDocument.Bookmarks
If aBookmark.Name Like "restart*" Then ' it's a restart point
Set RestartPoint = aBookmark.Range
RestartPoint.Collapse wdCollapseEnd
RestartPoint.MoveEnd unit:=wdCharacter, Count:=-1
With RestartPoint.ListFormat
.ApplyListTemplate .ListTemplate, ContinuePreviousList:=False
End With
aBookmark.Delete
End If
Next aBookmark
End Sub
After a paste into a different document, or an update to the style, you would need first to reset the paragraph formatting, so as to reapply the correct numbering scheme for the current document, and then reapply the restarts which will have been lost on the reset. The final example illustrates this.
Public Sub ReapplyLists()
' Sample macro to correct errors after paste
' to another document and style changes
Dim aPara As Paragraph
Dim aBookmark As Bookmark
Dim StyleName As String
Dim RestartPoint As Range
' reset the paragraph formatting of the style if the paragraph
' should be numbered in this document
For Each aPara In ActiveDocument.Paragraphs
StyleName = aPara.Style
If ActiveDocument.Styles(StyleName).ListLevelNumber > 0 Then
aPara.Reset
End If
Next aPara
' reapply restarts to bookmarked paragraphs and tidy up
For Each aBookmark In ActiveDocument.Bookmarks
If aBookmark.Name Like "restart*" Then ' it's a restart
Set RestartPoint = aBookmark.Range
RestartPoint.Collapse wdCollapseEnd
RestartPoint.MoveEnd unit:=wdCharacter, Count:=-1
With RestartPoint.ListFormat
.ApplyListTemplate .ListTemplate, _
ContinuePreviousList:=False
End With
aBookmark.Delete
End If
Next aBookmark
End Sub