Skip to main content

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  

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
  2. Hi MuthuKumar,

    Thanks for providing this tutorial.
    Do you know if it would be also possible to replace one of the words with an image which is locally stored?

    Kind regards,


    Marcel

    ReplyDelete
    Replies
    1. Hi Marcel, yes you can, and this is how http://alemiralles.blogspot.com.ar/2013/08/how-to-replace-text-with-images-on-word.html

      Hope this helps!

      Delete
  3. Thanks Amiralles, very useful
    Hi MuthuKumar,
    Try to use Aspose.Words for .NET
    There are good code examples in documentation section. I am sure it can solve your probelm. thanks

    ReplyDelete
  4. how can i insert pictures???? Please help

    ReplyDelete
    Replies
    1. this is how http://alemiralles.blogspot.com.ar/2013/08/how-to-replace-text-with-images-on-word.html
      ;)

      Delete
    2. Thanks helped a lot. Keep up the good work..

      Delete
  5. Check out Docentric toolkit:
    www.docentric.com
    It is a template based document generation toolkit for .NET where you use MS Word to create a template (docx) containing various tags/placeholders and populate it with it's report engine that is 100% .NET and does not rely on MS Word.

    I completely agree with the author about how tedious is to create even the most simple solution using Open XML SDK. Usually it is a lot of effort and many times leads to corrupt documents. But in my opinion Office COM is still a bad doc gen solution although it is a much simpler approach/technique - it is unstable, causes memory/process leaks and should in my view be always avoided.

    ReplyDelete
  6. Valuable information. Thanks for sharing. I actually felt that using templates in your presentation really raise your impression. I have also made a blog and hope you all will like it.
    http://slidehunter-usa.blogspot.in/2015/02/get-creative-office-templates-from.html

    ReplyDelete
    Replies
    1. I'll try one of them in my next presentation. Thanks.

      Delete
  7. Hi Could you please let me know how to use word teamplate dynamically assign values from a Data base. And for each iteration a new document to be created from the template. For example my Word template have a Name field as you mentioned and now i have to dynamically replace that name field with the data from data base. Also need one document per each record. suppose i have some 10 records(i.e Names) in my data base. please share the code. am a novice to this COM objects.

    ReplyDelete
    Replies
    1. Hi Satya, I guess I wouldn't use COM to do that. I'll try to go with something simple, like a plain old for loop and use some names convention to save each document.

      Suppose you query your database and store the result into a variable called tbl, you could do something like this:

      for(var i = 0; i < tbl.Rows.Count; i++) {
      //replace text with tbl.Rows["Name"] // <= most of the code in this post can be used as is.
      doc.SaveAs("names_" + i.ToString());//<= Save using a naming convention
      }

      And you are all set.

      Delete
  8. This comment has been removed by a blog administrator.

    ReplyDelete
  9. hello,
    Can you do this with textboxes? so that if you typ something in the textbox that it will replace in the template.

    kind regards

    ReplyDelete
  10. I'm working with MS Word now and this is a great help
    website

    ReplyDelete
  11. Hello please try out www.zetword.com
    It's a great .net application

    ReplyDelete
  12. This comment has been removed by the author.

    ReplyDelete
  13. How can i enter values from the service using this from another method is there a way pls help me

    ReplyDelete

Post a Comment

Popular posts from this blog

Migrating an ASP.NET MVC 4 app from Azure websites to WinHost

About a week ago I've to migrate an ASP.NET MVC 4/EF5 application from Azure websites to WinHost. While the process was really smooth, there were some caveats related to database connections that I want to share with you. Create and setup the ftp profile on VS and configure the connection string was really easy, WinHost provide you those values and there is nothing special here. But once you deploy your website and try to see it online, you may get the “yellow screen of dead” with the message: "A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)" Assuming you wrote the connection string properly, this happens because you cannot use the default connection name in your web.c...

How to show excel files inside the .NET Webbrowser Control

If you are reading this, chances are you been banging your head against the wall for a couple of hours (or even days) trying to show excel files inside the WinForms webbrowser control. Possible reasons you ended up in here: You had working code that got broke after upgrading from Win 7. Your code doesn’t work the same way between machines running different (newer) versions of IE. A download box pops up every time your app tries to show an excel file inside the webbrowser control (you wanna show the actual content). You just have no clue on how to get excel working into the .NET embedded webbrowser control. You are trying to implement IInternetSecurityManager and don’t know where to start. (Or how don’t know how to delegate calls to your security manager). Among many other, maybe….. Yes, COM is a PITA, so is ActiveX and IE (Embedded or full for that matter). And no, showing excel files inside the webbrowser control shouldn’t be that hard, but sometimes we have...

How to replace text with images on Word documents using C#

This post it’s a reply to a question I got from a previous post that shows how to work with Word templates from C# code . If you haven’t read it, I recommend to do so because I’m not going into details here. But basically it was about how to create a Word document from a template and perform same text manipulation. So, the question from Marcel Kieboom  was “Do you know if it would be also possible to replace one of the words with an image which is locally stored?” The answer is yes, and this is how you can do that. Based on the same convention I had used in the previous post, I should have a template like this: What I’m trying to do here is replace the text [angus-young] for an actual pic of Angus. The technique I’m using it’s pretty common on web sites and basically consist in have an image with a matching name for each keyword I want to replace and then create the image path dynamically. This is the C# code to do that. * When I execute t...