Log in

View Full Version : Problem Deleteing Content Controls



Jfp87
06-15-2015, 05:09 AM
Guys,

The code segment below for deleting all cc's within a document always misses out particular cc's....can anyone tell me what's went wrong? The particular cc's specified are never deleted (as planned)....but some of the other cc's still remain. I've included some of the code i've used for populating the cc's just for reference.


If strDocSubHeading = vbNullString Then
.SelectContentControlsByTitle("Subject").Item(1).Delete
Else
.SelectContentControlsByTitle("Subject").Item(1).Range.Text = "(" & strDocSubHeading & ")"
End If

.SelectContentControlsByTitle("Title").Item(1).Range.Text = oFrmPassed.txtTitle
.SelectContentControlsByTitle("Manager").Item(1).Range.Text = strWPDocNumber

For Each oRng In .StoryRanges
For Each oCC In oRng.ContentControls
If oCC.Title = "Status" Or oCC.Title = "Publish Date" Then
'Do nothing
Else
oCC.Delete
End If
Next oCC
Next oRng

cheers,
Joe

gmayor
06-15-2015, 06:09 AM
If you want to delete all CCs except one titled 'Status' or one titled 'Publish Date' then the following should suffice. If you want to delete ALL content controls then remove the two conditional statements.


Dim oStory As Range
Dim oCC As ContentControl
For Each oStory In ActiveDocument.StoryRanges
For Each oCC In oStory.ContentControls
If Not oCC.Title = "Status" And Not oCC.Title = "Publish Date" Then
oCC.Delete
End If
If oStory.StoryType <> wdMainTextStory Then
While Not (oStory.NextStoryRange Is Nothing)
Set oStory = oStory.NextStoryRange
If Not oCC.Title = "Status" And Not oCC.Title = "Publish Date" Then
oCC.Delete
End If
Wend
End If
Next oCC
Next oStory

Jfp87
06-15-2015, 07:36 AM
Thanks for that gmayor. Unfortunately I am still getting the exact same result; some of the CC's are not being deleted. Even within the footer, there are some CC's which have been processed and others that haven't.

I will need to go through this throughly but my personal feeling is that it is something connected with .selectContentControlsByTitle in the data population stage.

Cheers,
Joe

Jay Freedman
06-21-2015, 01:37 PM
Joe, looking at the CC's that appear not to be processed, are the actual content controls still there, or is it just the text that they contained before the macro ran -- now without the control containers?

If there is something in a content control when you call oCC.Delete, that something will be left as ordinary text; only the container is deleted. If you want the whole thing gone, you must first call oCC.Range.Delete and then call oCC.Delete -- the first statement will empty the content control (leaving the placeholder text temporarily) and then the second statement will remove the container and leave nothing.

Jfp87
06-22-2015, 03:55 AM
Jay, the actual content control containers are still there. What's puzzling is that some get deleted and some don't.

Still not figured this out yet.

Joe

gmayor
06-22-2015, 04:00 AM
Can you post your document (Go Advanced)?

gmaxey
06-22-2015, 04:06 AM
Joe,

If the CC is located in a shape text frame in a footer or header the code posted won't see it. Try:


Option Explicit
Public Sub ProcessAllCCs()
Dim oRngStory As Word.Range
Dim lngValidator As Long
Dim oShp As Shape
'Fix the skipped blank Header/Footer problem
lngValidator = ActiveDocument.Sections(1).Headers(1).Range.StoryType
'Iterate through all story types in the current document
For Each oRngStory In ActiveDocument.StoryRanges
'Iterate through all linked stories
Do
ProcessRange oRngStory
On Error Resume Next
Select Case oRngStory.StoryType
Case 6, 7, 8, 9, 10, 11
If oRngStory.ShapeRange.Count > 0 Then
For Each oShp In oRngStory.ShapeRange
If oShp.TextFrame.HasText Then
ProcessRange oShp.TextFrame.TextRange
End If
Next
End If
Case Else
'Do Nothing
End Select
On Error GoTo 0
'Get next linked story (if any)
Set oRngStory = oRngStory.NextStoryRange
Loop Until oRngStory Is Nothing
Next
lbl_Exit:
Exit Sub
End Sub
Public Sub ProcessRange(ByVal oRngStory As Word.Range)
Dim lngIndex As Long
For lngIndex = oRngStory.ContentControls.Count To 1 Step -1
With oRngStory.ContentControls(lngIndex)
Select Case .Title
Case "Status", "Publish Date": 'Do nothing
Case Else
.Range.Delete
.Delete
End Select
End With
Next lngIndex
End Sub

gmaxey
06-22-2015, 04:43 AM
I think I've found the issue (assuming I understand it). For some reason a for Each Loop will skip every other CC showing placeholder text. To illustrate. Put four plain text CCs showing placeholder text in the header and run:


For Each oCC In ActiveDocument.Sections(1).Headers(1).Range.ContentControls
oCC.Delete
Next oCC


Only first and third are deleted.

A For .Count to 1 Step - 1 works though.

Jay Freedman
06-22-2015, 10:34 AM
Greg, I see that's true in the Headers, but the same code applied to ActiveDocument.Range.ContentControls does delete all the content controls.

It's always been true that some collections in the object model recalculate their indexes when you delete items in a For Each loop, causing the every-other-one bug. (If you delete the first item, the formerly second item gets its index set equal to 1, the formerly third one gets index 2, and the invisible internal loop counter gets incremented from 1 to 2; so the next candidate to be deleted is the original third one.) Other collections treat a For Each loop correctly.

This one's a stumper, though, because you'd think that the ContentControls collection would behave the same in the main story and in the Headers, but clearly it doesn't.

The bottom line is, when deleting from a collection -- any collection -- never use For Each.

gmaxey
06-22-2015, 10:50 AM
Jay.

Right. That is why I said for some reason. I observed the same behavior as you, but I was in a rush to get off to welding classes and didn't have time to fully lay it out like you did. Thanks.

Jfp87
06-22-2015, 01:54 PM
Guys,

Thanks for the input. When I have time to test it out I will let you know my results...although I am assuming you already know that it will work!

So when deleting from a collection, never use a For Each..Loop, and in this case I will try using For x = .count to 1 step -1

Joe

gmaxey
06-22-2015, 02:02 PM
Yes and if the CCs are in the text frame of a shape in the header or the footer you have to explicitly processes those shapes.