Search code examples
c#ms-wordmailmerge

How do you mail merge a word document in c#


What I'm trying to achieve

In my c# application I would like to generate a report (word document) from data in my application, I figured that the best way to do this would be to perform something like a mail merge using the data source from my application.

What I've tried

  1. I tried following this Mail Merge into word however this uses GemBox which you need to pay for
  2. I have tried using Microsoft.Office.Interop.Word however I fell short when I didn't know how to reference the saved template document:

    Dictionary<string, string> MailMerge = new Dictionary<string, string>()
        {
            { "ID", "123" },
            { "Name", "Test" },
            { "Address1", "Test" },
            { "Address2", "Test" },
            { "Address3", "Test" },
            { "Address4", "Test" },
            { "PostCode", "Test" },
            { "Year End", "Test" },
            { "SicCode", "123" },
        };
    
        Document doc = new Document();
        doc.MailMerge.Execute(MailMerge);
    

Summary

I'm looking for some guidance as to what to research further as I believe there must be a 'standard' way of doing this.


Solution

  • This is quite simple by using Microsoft.Office.Interop.Word. Here is a simple step by step tutorial on how to do this.

    The code to replace a mergefield with a string is like this:

    public static void TextToWord(string pWordDoc, string pMergeField, string pValue)
    {
        Object oMissing = System.Reflection.Missing.Value;
        Object oTrue = true;
        Object oFalse = false;
        Word.Application oWord = new Word.Application();
        Word.Document oWordDoc = new Word.Document();
        oWord.Visible = true;
        Object oTemplatePath = pWordDoc;
        oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing);
        foreach (Word.Field myMergeField in oWordDoc.Fields)
        {
            Word.Range rngFieldCode = myMergeField.Code;
            String fieldText = rngFieldCode.Text;
            if (fieldText.StartsWith(" MERGEFIELD"))
            {
                Int32 endMerge = fieldText.IndexOf("\\");
                Int32 fieldNameLength = fieldText.Length - endMerge;
                String fieldName = fieldText.Substring(11, endMerge - 11);
                fieldName = fieldName.Trim();
                if (fieldName == pMergeField)
                {
                    myMergeField.Select();
                    oWord.Selection.TypeText(pValue);
                }
            }
        }
    }
    

    originally posted here and here

    In case you wish to use a dictionary to replace many fields at once use the code below:

    public static void TextToWord(string pWordDoc, Dictionary<string, string> pDictionaryMerge)
        {
            Object oMissing = System.Reflection.Missing.Value;
            Object oTrue = true;
            Object oFalse = false;
            Microsoft.Office.Interop.Word.Application oWord = new Microsoft.Office.Interop.Word.Application();
            Microsoft.Office.Interop.Word.Document oWordDoc = new Microsoft.Office.Interop.Word.Document();
            oWord.Visible = true;
            Object oTemplatePath = pWordDoc;
            oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing);
    
            foreach (Microsoft.Office.Interop.Word.Field myMergeField in oWordDoc.Fields)
            {
                Microsoft.Office.Interop.Word.Range rngFieldCode = myMergeField.Code;
                String fieldText = rngFieldCode.Text;
                if (fieldText.StartsWith(" MERGEFIELD"))
                {
                    Int32 endMerge = fieldText.IndexOf("\\");
                    Int32 fieldNameLength = fieldText.Length - endMerge;
                    String fieldName = fieldText.Substring(11, endMerge - 11);
                    fieldName = fieldName.Trim();
                    foreach (var item in pDictionaryMerge)
                    {
                        if (fieldName == item.Key)
                        {
                            myMergeField.Select();
                            oWord.Selection.TypeText(item.Value);
                        }
                    }
                }
            }
        }