Explanation of vba code in a word document having .docm extension - vba

I have a Microsoft Word document with .docm format. A first glance it does not contain any macros (as when clicking the following on the ribbon; View -> Macros -> View macros pops up a window having an empty list).
But when enabling the Developer ribbon tab, and clicking the Visual Basic icon there, and then selecting the Document and ContentControlonEnter from the dropdowns in the VB window the following code appears:
Private Sub Document_ContentControlOnEnter(ByVal ContentControl As ContentControl)
Dim i As Long, j As Long
With ActiveDocument
If ContentControl.Title = "Classification" Then
ContentControl.DropdownListEntries.Clear
For i = 1 To .ContentControls.Count
If Left(.ContentControls(i).Title, 5) = "Level" Then
j = j + 1
ContentControl.DropdownListEntries.Add Text:=j & " - " & .ContentControls(i).Range.Text
End If
Next
End If
End With
End Sub
Selecting the other options in the dropdowns give only "blank" code (that is they contain only function declarations followed by theEnd keyword).
My question is what is the code meant to do?
*
Details:
The Word document in question contains hyperlinks to parts of the same document and a couple of links to Word files and Excel files of the same folder. It also contains lots of content control boxes, which I'm guessing is the focus of the code (as the code contains the ContentControl keyword)

Content controls can trigger macros when the user enters and exits them. Microsoft made the design decision that all content controls should trigger the same "events" - Document_ContentControlOnEnter / Document_ContentControlOnExit - and that the code in the event needs to check which content control was entered / exited.
Content controls are considered as part of the Document because the Document can trigger events. That's why they're in (and MUST be in) the ThisDocument class module.
(Note: View Macros can only show you PUBLIC SUB procedures with no arguments that are located in "normal" code modules. Any Private Sub, any Function, anything that takes a parameter and anything in a class module will not appear in that list. So you can't use that list to determine whether a document contains any code.)
The If ContentControl.Title = "Classification" Then checks which content control was entered. (Note: it usually makes more sense to use Select Case rather than If, especially when the event needs to distinguis between multiple content controls.) What's inside the If only executes if it was a content control with the Title "Classification". (Note that more than one content control can have the same Title, so more than one content control could run the code.)
If another content control is entered, the event is still fired, but nothing happens (in this case).
Catalin Pop correctly explained that the code is, in essence, "resetting" the drop down list.
Legacy Form fields use a similar pattern - macros can fire when the user enters/exits an form field. But the design for that was you had to create a Public Sub and assign that to the form field in the Properties.

I think the logic here is quite simple.
Basically the code searches for a content control named Classification within the entire document.
After it finds it, it clears all of its drowdown entries - like a reset.
After the cleaning part it again searches through the entire document for all content control that start with word "Level" and it collect the text for those controls and their order in appearance.
With this info collected it then fills the dropdown optios for the classification control above. (e.g. 1 Level X, 2 Level Y.. - based on what it finds in the document for controls starting with Level in their name)

Related

Fire Subroutine when user leaves a date field ContentControl Word VBA

Edit: I've updated the post with more info.
I have a Content Control inside a header in Word in which I have a date time picker. I'm trying to fire the _ContentControlOnExit event when the user leaves the focus (blurs) of the picker.
Let's suppose I've manually created a Content Control and I've assigned it a Date Picker. I've also tagged it with the value date.
I want that each time the date is changed, I perform a subroutine that will insert a text value to another ContentControl tagged tide-level. I tried the code below with no success.
Please, note that the date ContentControl is inside a header in the Word Document.
Private Sub ActiveDocment_ContentControlOnExit(ByVal ContentControl As ContentControl, Cancel As Boolean)
If (ContentControl.Type = wdContentControlDate) Then
MsgBox "Let's do it! Write the tide levels"
dateObj = ActiveDocument.SelectContentControlsByTag("tide-level")
dateObj.Range.Text = "wwwoohooo Tide Levels!"
Cancel = True
End If
End Sub
I remember reading somewhere that whenever you have content in the header, it seems things get problematic...
Any ideas?
P.S:
Currently using Word 365 - VBA
Based on the name of the procedure in the question - ActiveDocment_ContentControlOnExit - it appears the event handler was not generated automatically by Word and that it is therefore not in the ThisDocument class module of the document that contains the content controls. The name of the event handler (generated by the VBA editor) is usually Document_ContentControlOnExit.
The content control event handlers must be in ThisDocument. Theoretically, they could be typed manually, but Word doesn't always recognize manually typed event handlers. So it's better to use the VBA Editor's automatic "stub" generation to get the structures:
Open the ThisDocument module for the document that contains the content control.
In the code page window, at the top left, select "Document" from the drop-down.
from the top-right select the event to be inserted.
At this point, the VBA editor will create the "stub" for you - all that's needed is the code to be executed.
Note about the content control being in the header: This event does fire as long as focus when exiting remains in the header. If, however, the user double-clicks in the document body in order to exit the header the event doesn't fire. (At least, not in my tests.) If this is a problem you may want to put this field in the body of the document with a second, linked content control in the header to reflect the selection. Doing this is a bit complex (requires a Custom XML Part in the document to manage the linked information), but the version of Word you're using should have a tool for setting it up.
the macro name should be:
Docment_ContentControlOnExit
NOT:
ActiveDocment_ContentControlOnExit

Macro to Modify Content Control Properties for Directory of Documents

I have over 300 documents with a table coverpage, within one of the cells is a content control box with incorrect properties (the title and the tag are both named wrong). I can so far create a macro to fix the properties but only after I click into the cell by opening each document one by one. Is there a way to run a macro that can find this content control box in a table and amend the properties and save?
To search for a Content Control with a certain Title and/or Tag in a document and then change the Title or Tag, you'd use code something like this ...
Dim cc As ContentControl
For Each cc In ActiveDocument.ContentControls
If cc.Range.Information(wdWithInTable) Then
If cc.Tag = "InErrorTag" And cc.Title = "InErrorTitle" Then
'then correct the Tag and Title
cc.Tag = "CorrectedTag"
cc.Title = "CorrectedTitle"
End If
End If
Next
To then perform this replacement in a batch process of updating multiple documents you need additional code.
There is a Wiki article Batch Editing MS Word Documents that provides cross platform (Windows and Mac) VBA code for that purpose. You can merge the article's code with the Content Control replacement code above to accomplish you task.

Word 2013 - Macro Reference in .docx file

I have a pretty large template (in terms of macros) and I've created a new module that is called when the user does a specified shortcut on the keyboard.
The Macro does nothing more but call "ThisDocument.HideComboBoxes".
"HideComboBoxes" is a Sub in ThisDocument, which does the obvious: hide all combo boxes in the document.
The code works fine as long as I'm working with the template.
If I render a new document out of it (a docx file) the shortcut does not work anymore (which is kinda obvious because the ThisDocument is now empty for the document).
How do I access the template's ThisDocument from within the document or how can I hide the combo boxes from within the docx?
Here's the code for hiding the comboboxes in the template's ThisDocument:
Sub HideComboBoxes()
Me.ComboBoxConfi.Width = 1
Me.ComboBoxConfi.Height = 1
Me.ComboBoxState.Width = 1
Me.ComboBoxState.Height = 1
End Sub
Thanks in advance
You need to put the code in a "normal" module. This will require changing the calls to the ActiveX controls, which is a pain, but works.
Assuming the ActiveX controls are managed on the document surface as InlineShapes a call would look like this:
Dim cbConfi as Object 'or as MsForms.ComboBox to get Intellisense
Set cbConfi = ActiveDocument.InlineShapes([indexvalue]).OLEFormat.Object
cbConfi.Width = 1
If you don't want to rely on the index value (position of the control in the InlineShapes collection) you can select the ActiveX control and assign a bookmark to it. Or you can loop the collection of ActiveX controls, check the Type and, if it's a OLE object, check whether the Class type is MSForms.Combobox and then via OLEFormat.Object.Name whether its the right one.

MS-Word VBA reference identification

I have a custom content control in Microsoft Word from a third party I am trying to resize the width and height of. Normal content control selection via VBA is not working because this control has no Title or Tag. However, if I manually select the object and resize it programmatically using "Selection.ShapeRange.Height = x" or ShapeRange.Width it does work. So to do it all programmatically I need to determine the name of the "selection" without having to manually select it.
Is there a way to "inspect" the complete reference to the currently selected object in word, so we can then get a starting point to work with it in VBA?
It's hard to know what type of object your dealing with. I tested this by inserting a blank ActiveX image control, selecting it and then running the macro. The code has two methods but one is commented out.
Sub FindName()
MsgBox (Selection.Fields.Item(1).OLEFormat.ClassType)
'MsgBox (Selection.InlineShapes.Item(1).OLEFormat.ClassType)
MsgBox (Selection.InlineShapes.Item(1).Field.Index)
MsgBox (Selection.InlineShapes.Item(1).AlternativeText)
'Show current name
MsgBox (Selection.Fields.Item(1).OLEFormat.Object.Name)
'Set new name
Selection.Fields.Item(1).OLEFormat.Object.Name = "Image5"
'Re-display name to show that it changed
MsgBox (Selection.Fields.Item(1).OLEFormat.Object.Name)
End Sub
The result was this:

Open multiple copies of word form?

I'm fair at Access vba but Word is a new dialect for me.
I work for a hospital that has an Electronic Medical Record (EMR). We need a specific format and structure for the Nurse’s Clinical Progress Notes that can’t be created and enforced in the EMR. I created a Word vba UserForm, "frmProgNote" attached to a document "ProgNote.doc". FrmProgNote" has textboxes that create the structure we need for documentation and there is a command button that when clicked sends the info from the form to bookmarks in ProgNote.doc and copies all text from the document, including the newly inserted text onto the clipboard. The user then pastes it into the EMR. This all works great (believe it or not) but now they want to have multiple copies of frmProgNote open at the same time so they can move between several patients at once.
I’ve worked on this for 2 days and just can’t get it. I found I could not open multiple instances of Word and have the same form open in more than one. I copied the document and form so now have ProgNote1.doc with frmProgNote1 and ProgNote2.doc with frmProgNote2. I can get both to open BUT if I open frmProgNote1 then open frmProgNote2 the only data I can copy comes from frmProgNote2; the copy button doesn’t copy anything from the first form. I can click on frm1 and get it to take new data but the copy button doesn’t work anymore. Any suggestions? Thanks so much.
The following code gives the basis for creating a new instance of a UserForm.
Private frmNewInstance As Object
Private Sub CommandButton1_Click()
Set frmNewInstance = UserForms.Add(Me.Name)
frmNewInstance.Show
End Sub
Private Sub UserForm_Terminate()
Set frmNewInstance = Nothing
End Sub
It is necessary to control the object-reference, setting it to Nothing when the form instance is closed.
Note that this process is not as robust or reliable as it would be in, for example, VB.NET or C#. In particular, it is more difficult to distinguish between the different instances of the form.
One approach to consider is to use the Tag property of the form:
frmNewInstance.Tag = "OtherOne"
frmNewInstance.Show