Search code examples
vbams-wordword-2010

Add a content control after an existing content control in word 2010 using vba


A little more detail:

  1. I am inserting (lots of) documents with content controls into a single document.
  2. One of the content controls in each doc is a title control (linked to document property), which naturally receives the same value as the destination document's title on insert.
  3. Renaming the control's title and or tag, using word or vba does not fix the problem (weird!)
  4. My proposed solution is to create a new control with a different name, copy across the .range.text from the original title control and then delete the title control.

I have a loop which goes through all the files that need changing which works fine. However, whatever I seem to do, any new controls that I create appear at the beginning of the document and not in the correct place (there is a control with a code for the document before it).

Ideas? As an aside is there any logical reason why changing the control names doesn't work?

Current code:

Sub FieldChanger()

Dim docCur As Document
Dim strCurPath As String
Dim strCurFile As String
Dim rngTitle As Range
Dim strTitle As String
Dim ccName As ContentControl

strCurPath = "C:\Users\User\Desktop\BGS\Final\"
strCurFile = Dir(strCurPath & "*.docx")

Do While strCurrentFile <> ""
    Set docCur = Application.Documents.Open(strCurPath & strCurFile)
        With docCur.ContentControls
            .Item(1).LockContents = False //Unlock outer content control
            Set rngTitle = .Item(3).Range
            strTitle = rngTitle.Text
            rngTitle = rngTitle.Move(wdCharacter, 1)
            ccName = rngTitle.ContentControls.Add(wdContentControlRichText) //This line throws a 4198 error
            ccName.Title = "ccName"
            ccName.Tag = "ccName"
            ccName.Range = strTitle
            ccName.LockContentControl = True
            .Item(3).LockContentControl = False
            .Item(3).Delete
            .Item(1).LockContents = True //Lock outer content control
        End With
    docCur.Save
    docCur.Close
    strCurFile = Dir
Loop

End Sub

Solution

  • As an aside is there any logical reason why changing the control names doesn't work?

    The Content Control (CC) name is just a name. Renaming the CC from "Title" doesn't change where Word gets the content from. Nor would naming a CC as "Title" cause Word to put the document's title string in the CC. If you create an empty document, insert the Title document property (as a CC) and look at the value of

    activedocument.ContentControls(1).XMLMapping.XPath

    you will probably see the value

    /ns1:coreProperties[1]/ns0:title[1]

    This is what tells Word that it needs to put the value of the Title builtin document property in the CC, and where to go to get it. You can link your own plain text CCs to builtin properties using the same mechanism, or you can link them to nodes in "Custom XML parts" of your own. But they don't have to be linked to anything.

    As for the code, how about something more like this (NB, I have also changed "strCurrentFile" to strCurFile). I wondered whether you really need to re-insert the CC value as a new CC (i.e. why not just remove the CC and leave its existing value there) but have assumed that you need the CC there.

    NB, as a general rule in VBA you need to use the Set keyword when setting the value of objects such as range variables and CCs. In theory you should also set objects to Nothing (e.g. Set rngTitle = Nothing) when you have finished with them. I haven't added that stuff here. In VB.NET you don't need to do either of those things.

    Dim docCur As Document
    Dim strCurPath As String
    Dim strCurFile As String
    Dim rngTitle As Range
    Dim strTitle As String
    Dim ccName As ContentControl
    
    strCurPath = "C:\a\test\"
    strCurFile = Dir(strCurPath & "*.docx")
    
    Do While strCurFile <> ""
        Set docCur = Application.Documents.Open(strCurPath & strCurFile)
            With docCur.ContentControls
                .Item(1).LockContents = False 'Unlock outer content control
                Set rngTitle = .Item(3).Range
                strTitle = rngTitle.Text
                ' we need the following line to ensure that deleting the range
                ' does not remove the CC prematurely
                .Item(3).Temporary = False
                rngTitle.Delete
                rngTitle.Collapse wdCollapseStart
                ' Delete the control here instead of later
                .Item(3).LockContentControl = False
                .Item(3).Delete
                Set ccName = rngTitle.ContentControls.Add(wdContentControlRichText) 
                ccName.Title = "ccName"
                ccName.Tag = "ccName"
                ccName.Range = strTitle
                ccName.LockContentControl = True
                .Item(1).LockContents = True 'Lock outer content control
            End With
        docCur.Save
        docCur.Close
        strCurFile = Dir
    Loop
    

    Comment consolidation...

    There are addins that may help, e.g. the databinding toolkit at cctw.codeplex.com (not checked that link recently)