ms-wordoffice-interopword-fieldfieldcodes

Primitive MailMerge using just delimited field names


Obviously the correct way for our app to generate a Word document based on a template is to encourage the admin users (who will look after the templates) to embed the correct merge fields or bookmarks in the template document.

However in the past we have found our typical admin user who ordinarily doesn't use MailMerge or any of the other "advanced" features in Word is significantly put off by having to use merge fields. We have tried doing it for them, producing documentation, lots of screenshots etc. But it's all "fiddly" for them.

They have dozens of templates (all just different kinds of really simple letters), and will want to modify them reasonably frequently.

What they would really like is to be able to just mark fields with a simple delimiter like a curly brace, which effectively marks a homemade merge field to our app (though Word is oblivious to its significance) as in:

Dear {CustomerSurname}

Then we can just pick up the field(s) with several lines of code as in:

w = New Word.Application
d = w.Documents.Open(...)
Dim mergedContent As String = d.Content.Text
mergedContent = mergedContent.Replace("{CustomerSurname}", Customer.Surname)
mergedContent = mergedContent.Replace("{CustomerPostcode}", Customer.Postcode)
d.Content.Text = mergedContent

This feels crude, but beautifully simple (for the end user).

Has anyone else gone down this route? Anything wrong with it? We would advise them not to use the "{" and "}" character elsewhere in the normal text of the document, but that's not really a significant limitation.

Speed? Wrapping the merge field across two lines? Other problems?


Solution

  • This is a part of my code that I used to find and replace. I tried your code first but that didn't work. This is based upon the VBA code that Word generates when you record a macro.

    range = document.Range()
    
    With range.Find
     .Text = "{" & name & "}"
     .Replacement.Text = NewValueHere
     .Forward = True
     .Wrap = Word.WdFindWrap.wdFindContinue
     .Format = False
     .MatchCase = True
     .MatchWholeWord = False
     .MatchWildcards = False
     .MatchSoundsLike = False
     .MatchAllWordForms = False
    End With
    range.Find.Execute(Replace:=Word.WdReplace.wdReplaceAll)
    

    I used this code because the documents needed to be compatible with the Office binary file formats. If you can use the Office 2007 format you don't need to have Word installed. Just unzip the document, find the word\document.xml file, do a String.Replace("[OldValue]", "New value"), save the file and zip it back to one package (docx file). The code I displayed here is pretty slow because I'm automating Word. Opening Word, editing 2 documents with 6 fields and closing the app takes 4 seconds on my pc.