locked
Tips for using content controls and building blocks from a dotm file. RRS feed

  • General discussion

  • So here I was; just left OpenOffice behind me due to several reasons and started with Word 2010. My goal: having a letter template which could fill out the address section and setup a personal reference field. For a rough example see:

    ...where the top of the picture resides in the header of my document.

    So, summing up the problems I've encountered and which I'm commenting on here:

    • Inserting single values into content controls (access by name)
    • Accessing the header of a document
    • Developing a macro without messing up the original template
    • Removing a line from the document
    • Inserting a blank line into the document
    • Inserting a building block into the document


    Accessing content controls (and a little more)

    I've done a lot of reading / searching and found many solutions which either involved directly patching into the xml source or which tried to bind the controls to an external data source. Really not what I had planned; I'm merely displaying an entry form where people can enter their data after which said data is implemented into the document.

    This was a litlte rough, even the documentation (in the vba editor) seemed to focus more on adding content controls to a document than how to access those. SO here is how I managed to solve it:

    Dim cc As ContentControl
                For Each cc In ActiveDocument.ContentControls
                    Select Case cc.Tag
                        Case "bedrijf"
                            cc.Range.Text = adresformulier.box_bedrijf
                        Case "tav"
                            If noTAV Then
                                cc.Delete
                                With ActiveDocument.Content
                                    .Sentences(4).Delete
                                    .Paragraphs.Add Range:=.Paragraphs(10).Range
                                End With
                            Else
                                naam = adresformulier.box_tav
                                cc.Range.Text = naam
                                aanhef = "Geachte " + naam
                                controle = ActiveDocument.Content.Find.Execute(FindText:="L.S.", MatchCase:=True, ReplaceWith:=aanhef)
                            End If

    So, what's happening here?

    I have several content controls in my document and by using a For Each I can iterate over every one of them. Because every content control has a tag (and I defined all of them, see screenshot) I can simply use a Select Case block in which I merely go over all the tags in my document, as illustrated above. It really is that simple.

    Actually inserting text is done by using the Text property (as explained in the manual). In this same manner I used the Delete method to get rid of a content control. As one could (and should) expect this only gets rid of the control. What about the rest?

    Well, here it gets peculiar. As you can see I'm using the ActiveDocument.Content.Sentences collection to point to a single sentence and then remove it. All's well you may think. Well, no...

    Because if you're then going to try and add a sentence you'll learn that there is a huge difference between sentences and paragraphs. There are a lot of empty lines between the end of my address block and the beginning of my letter; this is done to make sure that my eventual letter will fit into a "windowed envelop". SO far, so good. Now, with the empty template open (so hardly any text) watch this:

    print ActiveDocument.Content.Sentences.Count
     11
    print ActiveDocument.Content.Paragraphs.Count
     19

    This is all from the 'Direct' window. Ok; unmentioned tip. In the VBA editor press "Control-G" and you have a 'Direct' window open in which you can test out a lot of stuff. Keep a method or function public and you can easily test its behavior right from here, very handy for developers I'd say!

    Ok, so back to the subject. In my document which contains lots of empty lines every empty line is basically picked up as a Paragraph. Because of that I'm actually inserting an empty parapgraph (Paragraphs.Add) and defined to range as to where to add this as yet another parapraph (pointing right in the middle of the empty lines between the header and my actually letter). It is because of this why you should also be very careful when using Sentences(x).Delete. DO not start counting lines and consider them all individual sentences, esp. not when using Content controls.



    Accessing the header of a document

    When I started out with vba this seemed impossible, but as soon as you're slowly becoming more familiar with it you'll pick up the logic behind it, after which issues like these become a whole lot easier:

    ActiveDocument.Sections.First.Headers(1).Range.ContentControls(1).Range.Text = ref

    Ok, so first I'm accessing the first section of my ActiveDocument and from there also access the first object in the Headers collection (which happens to be the header I'm after). Within the range of the header I'm accessing the first Content control which I then insert with a value which I want to use.

    This also works easily with checking up on the amount of sentences in the header for example...

    print ActiveDocument.Content.Sections.First.Headers(1).Range.Sentences.Count
     2

    Which does indeed consist of 2 lines. And because I'm not using any empty lines there are also no oddities going on between sentences vs. paragraphs.

    This section actually goes one on one with the tip on how to safely develop macro's while keeping your templates intact. Its really simply; open a new document based on your template while you're working on it.

    If you then open up the VBA editor (alt-f11) you'll see all documents together with the normal.dotm. The document you're working on now, the original template document and, as said, the normal.dotm template.

    And this immediately illustrates the problems I've encountered when trying to insert some building blocks.

    My setup is that the moment you create a new document based on my template the macro will automatically start (using the "Document_New" method in the 'ThisDocument' section of the template). And the building blocks are actually saved into the original template file.

    At first I started using "Word.Templates(1).BuildingBlockEntries(1).Insert" which indeed worked as planned.

    Small sidestep...  Here once again the Direct window proved to be invaluable. Because what entry did I really need? While keeping the original template open I accessed the VBA macro and tried:

    print word.Templates.count
    2

    Aha!  so....

    print word.Templates(1).Name
    Standaard brief.dotm
    print word.Templates(2).Name
    Normal.dotm

    Yet eventually this got me into some serious trouble whenever I had more documents opened up. So eventually I came up with this (full) solution:

    Word.Templates(Word.Templates.Count - 1).BuildingBlockEntries(1).Insert (ActiveDocument.Content.Paragraphs(15))

    I'm inserting a building block from my own Word template and into the currently active document; right within the 15th line ("paragraph).

    And there you have it, several issues I've encountered and managed to solve in the way illustrated above...

    Disclaimer: I'm still very new to VBA and as such I cannot rule out that some of the solutions I've mentioned above may actually be tied to my own specific setup. If you're interested in some of the parts above I suggest to rule this option out by using the Direct window. Simply try some of the above out in your current document right from within the VBA editor to see how it turns out. IMO that is the easiest way to approach this.

    RIGHT, I hope this might prove useful for someone.

    • Edited by ShelLuser Wednesday, September 7, 2011 1:47 AM
    Wednesday, September 7, 2011 1:41 AM

All replies

  • Hi,

    Thank you very much for your time and efforts on this.

    Your post will benefit many other users, and we really value having you as a Microsoft customer to help us to make our programs better.

    Have a nice day!


    Sincerely,

    Max Meng
    Forum Support
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    If you have any feedback on our support, please contact
    tnmff@microsoft.com.

    • Edited by Max Meng Tuesday, September 27, 2011 3:56 AM
    Thursday, September 8, 2011 5:32 AM