Search code examples
vbams-wordword-contentcontrol

VBA Word Insert text dynamically - Problems with ContentControl - Alternatives?


I am struggling quite a bit with ContentControl(s) in my Word VBA project. There are a number of content control text fields which all have the same name (they have the same name because at the beginning the total number of required fields is not known, so I copy and paste the fields as many times as required). Now I want to loop through the content control fields and change the name of the fields based on the index of the individual items (e.g. first field in the document = "One", second field in the document = "two" and so on).

However, as mentioned in other threads, the index of the content control element does not correspond to its position in the document (I do not know, what it corresponds to). Thus, instead of getting the fields in order, I get e.g. "four" --> "one" --> "three" --> "two" (or any other possible combination).

The content of the fields is coming from UserForm TextBoxes. The text boxes are named Text_Box_1 to Text_Box_4:

Private Sub Test() 'Note: The actual code is more complex, this is just to demonstrate my problem.

Dim i As Integer

UserForm1.TextBox1 = "one"
UserForm1.TextBox2 = "two"
UserForm1.TextBox3 = "three"
UserForm1.TextBox4 = "four"    

For i = 1 To 4 - 1 'Since there are four text boxes in the UserForm in this example, the text snippet containing the text field gets copied and pasted three times; Note: Here the number of textboxes is pre-determined and fixed, in the actual project, it is variable.
    ActiveDocument.Bookmarks(Index:="Copy").Range.Copy '
    ActiveDocument.Bookmarks(Index:="Paste").Range.Paste
Next i

For i = 1 To 4 'This code is supposed to loop through the four content control text fields and insert text from the corresponding UserForm text box. However, content control text field 1, unfortunately does no correspond to UserForm.TextBox1 for some reason.
    ActiveDocument.SelectContentControlsByTitle("Number").Item(i).Range.Text = UserForm1.Controls("TextBox" & i)
Next i

End Sub

Before running the code

After runnning the code

Is there any way to name to content control fields in the right order? If not, what would be an alternative method to achieve my goals. I think legacy text fields are not an option, since the document has to be protected; I have not looked into ActiveX text fields too much; Text boxes (shapes) might be another option, but they might have their own drawbacks.

It is really frustrating that the content control fields are behaving so weirdly and that something seemingly very simple and straight-forward can be so complicated (at least for me).

edit: Fixed a typo in the title.


Solution

  • Rather than use copy and paste I would insert the required text and content controls in my routine, something like this.

    Private Sub Test()
    
       Dim i As Integer
    
       UserForm1.TextBox1 = "one"
       UserForm1.TextBox2 = "two"
       UserForm1.TextBox3 = "three"
       UserForm1.TextBox4 = "four"
       
       Dim cc As ContentControl
       Dim rng As Range
       Dim ccLocation  As Range
    
       For i = 4 To 1 Step -1  'Insert in reverse order to ensure that they are correct in the document
          Set rng = ActiveDocument.Bookmarks("Paste").Range
          rng.InsertAfter Text:="Number: "
          rng.Collapse wdCollapseEnd
          Set ccLocation = rng.Duplicate
          rng.InsertAfter vbCr & "----------------------------------------" & vbCr
          Set cc = ccLocation.ContentControls.Add(wdContentControlText)
          cc.Range.Text = UserForm1.Controls("TextBox" & i).Text
          cc.Title = "Number" & i
       Next i
    
    End Sub
    

    If you cannot delete the existing content and must work with what you have then you could use the following:

    Private Sub Test()
    
       Dim i As Integer
    
       UserForm1.TextBox1 = "one"
       UserForm1.TextBox2 = "two"
       UserForm1.TextBox3 = "three"
       UserForm1.TextBox4 = "four"
       
       ActiveDocument.SelectContentControlsByTitle("Number").Item(i).Range.Text = UserForm1.Controls("TextBox1").Text
    
       Dim cc As ContentControl
       Dim rng As Range
       Dim ccLocation  As Range
    
       For i = 4 To 2 Step -1  'Insert in reverse order to ensure that they are correct in the document
          Set rng = ActiveDocument.Bookmarks("Paste").Range
          rng.InsertAfter Text:="Number: "
          rng.Collapse wdCollapseEnd
          Set ccLocation = rng.Duplicate
          rng.InsertAfter vbCr & "----------------------------------------" & vbCr
          Set cc = ccLocation.ContentControls.Add(wdContentControlText)
          cc.Range.Text = UserForm1.Controls("TextBox" & i).Text
          cc.Title = "Number" & i
       Next i
    
    End Sub