MailMergeBookmarks.cs
//
// This code is part of GrapeCity Documents for Word samples.
// Copyright (c) GrapeCity, Inc. All rights reserved.
//
using System;
using System.IO;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using GrapeCity.Documents.Word;

namespace GcWordWeb.Samples
{
    // This sample demonstrates one possible approach to generating documents
    // using a specially prepared DOCX as the template, and filled with data programmatically,
    // useful for example in mail merge applications.
    // Here the template document has parts that should be replaced with data marked
    // with bookmarks, each bookmark defined on the whole part that needs replacing.
    // For convenience, such parts in the document text are enclosed in square brackets,
    // with text equal to the corresponding bookmark's name.
    // In MS Word, use Insert | Bookmarks to inspect or add bookmarks.
    public class MailMergeBookmarks
    {
        public GcWordDocument CreateDocx()
        {
            GcWordDocument doc = new GcWordDocument();
            doc.Load(Path.Combine("Resources", "WordDocs", "MailMergeBmk-tpl.docx"));

            var bmks = doc.Body.Bookmarks;

            // Replace bookmarks with actual data. In a real life sample,
            // this would usually be a loop over a data source.
            setBmkText("title", "Mr.");
            setBmkText("surname", "Smith");
            setBmkText("address", "123 Bits Dr.");
            setBmkText("city", "Byteville");
            setBmkText("state", "VT");
            setBmkText("zip", "12345");
            setBmkText("country", "U.S.A.");

            // Done:
            return doc;

            // Method to replace a bookmarked text with a specified value.
            // Note:
            // - We replace the first bookmarked run with the specified value,
            //   so the replacement will be formatted as the first bookmarked run;
            // - MS Word may have created multiple runs for a bookmarked text,
            //   so we need to make sure we remove all but the first run.
            void setBmkText(string bmk, string value)
            {
                if (!bmks.Contains(bmk))
                    return;
                var t = bmks[bmk].GetRange();
                t.Texts[0].Value = value;
                for (int i = t.Texts.Count - 1; i > 0; --i)
                    t.Texts[i].Delete();
            }
        }
    }
}