Friday, November 23, 2012

How to create MS Word documents from Office templates using C#


The OpenXML SDK allows you to do pretty much anything you want with office files such as Excel, Word, etc… While many people like this library, I found it complex, unintuitive and poorly documented, not to mention the awful xml format that uses under the hood to represent the documents, styles, etc. So I decided not to use it and build my own solution. If you, like me, don’t like that library, you will find in this post an alternative approach to build word documents from templates using c#.

A neat trick to work with Office is to use the macro recorder to understand how things work. The macro recorder allows you to start a macro, do something by hand, stop it, and then take a look at the generated VBA code. Once you do this, you are pretty much set.

This is how it looks the template I’am going to use.



Note: save the file as a Word template (.dotx)

This is the code to create Word documents from C#:


By running the code, you should get a document that looks like this.



Note that the font, format, styles, etc. are the same that we defined in the template (Is not just about replacing text)

By the way, don't forget to reference the right version Word interop assembly.



You can grab the code from here  

3 comments:

  1. If we want to replace more number of words, then how to do it? if i replace more words by finding the word, it is replacing only the word that is given in the last..

    ReplyDelete
    Replies
    1. Hi MuthuKumar, I usually do something like this:

      public class WordWrapper : IWordWrapper {
      private readonly string _templatePath;
      private Application _app;
      private Document _doc;
      private Selection _sel;
      private bool _isDisposed;

      public WordWrapper(string templatePath) {
      _app = new Application();
      _templatePath = templatePath;
      }

      public void OpenTemplate() {
      ValidateFileExistAndIsWordTemplate();

      _doc = _app.Documents.Add(Path.GetFullPath(_templatePath), Visible: false);
      _doc.Activate();
      _sel = _app.Selection;
      }

      public virtual void FindAndReplaceText(string keyword, string replacement) {
      _sel.Find.Text = keyword.ToTemplateFormat();
      _sel.Find.Replacement.Text = replacement;
      _sel.Find.Wrap = WdFindWrap.wdFindContinue;
      _sel.Find.Forward = true;
      _sel.Find.Format = false;
      _sel.Find.MatchCase = false;
      _sel.Find.MatchWholeWord = false;
      _sel.Find.Execute(Replace: WdReplace.wdReplaceAll);
      }
      //some more code but not related to the point...
      }

      And call the function like this:

      _word.OpenTemplate();
      foreach (var keyword in Keywords.Keys)
      _word.FindAndReplaceText(keyword, Keywords[keyword]);

      Where Keywords contains both the placeholder and the value to be put inside that place holder when find a match.
      //i.e. {"[user]","amiralles"},{"[customer]","pipe"}, etc...
      If what do you wanna do is to replace the same place holder, let say [user], with different values, such as iterating over an users collection and do the replacing for each occurrence. I'm afraid you can't do that....
      You can try to start the macro recorder in word, do it by hand and see what code was generated by the macro recorder and try to mimic that code in C# but I've never tried it myself, sorry :\.

      Delete