Category Archives: WordWriter

How to add lists into a repeat block with WordTemplate

Problem

Creating lists, ordered or bulleted, using the template object is possible using repeat blocks. However, sometimes you may wish to include a list inside another repeat block, but you run into the following hurdles:

  • WordTemplate does not support nested repeat blocks
  • WordApplication can dynamically insert lists, but it is not available in WordWriter Standard Edition
  • WordTemplate nesting and grouping can also handle nested lists, but is only available in Enterprise Edition.

Solution

Using the WordTemplate object, one cannot populate a fully functional list within a repeat block. However, it is possible to emulate the look of such lists. The general idea is to concatenate the list items into one formatted string that Word displays as a list. These strings can be stored in any database. This solution works for both binary (.doc) and OOXML (.docx) formats in office 2007.

For bulleted lists, use the following format:
“• First item\r\n• Second item”

For numbered lists, use the following format:
“1) First item\r\n2) Second item”
Or
“1. First item\r\n2. Second item”

Note that the generic string format that will be displayed as a list in Word uses the two characters “\r\n” as the separator between the items.

Reading form values with WordApplication

Problem

The WordApplication API can represent several Word elements that can appear in documents. These are outlined in Word file representation in WordApplication. These elements do not include form components, such as check boxes or text fields.

However, WordApplication can detect form elements on a basic level and some components can be parsed minimally.

Solution

WordApplication does not support manipulating form elements, but it is possible to get a handle on form fields using Document.GetElements(Element.Type.Field). This will return all the field elements in the document, even if they are not Mergefields or Hyperlinks.

GetElements() returns a collection of generic Element objects. Element is the parent class for all other objects represented by WordApplication.

The contents of an Element can be read in Element.Text, which is a text of the content contained in the Element.

For a few form fields, such as text fields, the value of the field will appear in Element.Text. Others, such as check boxes, will show a string form of the object (e.g. “FORMCHECKBOX”).

This is not officially supported in the WordApplication API, so we cannot guarantee that the form field values can be parsed by WordWriter.

WordWriter support for text boxes

Problem

You have a word Document that contains texboxes. You want to know if WordWriter supports modifying or creating textboxes.

Solution

WordTemplate will populate any merge fields that are placed inside of a text box. This is largely because WordTemplate does not parse the full document and ignores the locations of merge fields.

If you need to search for and replace text that appears in text boxes, you can do so with the WordTemplate object. More details are available in this post.

Unfortunately, WordApplication does not support creating or modifying text boxes. The full list of elements recognized by WordApplication is outlined in this documentation article.

How to remove WordWriter from the Global Assembly Cache

Problem

In OfficeWriter version 4.6.0 and below, the installer placed WordWriter in the Global Assembly Cache (GAC). This was to enable you to use WordWriter in a COM application, via a COM-Callable Wrapper. However, if you are not using WordWriter in COM or if you prefer not to have assemblies in the GAC, you may wish to remove WordWriter from the GAC.

Solution

General WordWriter uninstallation instructions can be found in our documentation.

To manage assemblies in the GAC, you can use the gacutil tool. The availability of this tool depends on the version of the .NET framework. You can find gacutil at the following locations:

  • For .NET 1.1: c:\Windows\Microsoft.NET\Framework\v1.1.xxxx
  • For .NET 2.0 through 3.5: c:\Program Files\Microsoft SDKs\Windows\v7.0A\Bin
  • For .NET 4.0: c:\Program Files\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools

On an x64 system, substitute Program Files (x86) for Program Files. The version of gacutil matches the version of the .NET framework. To see the version of gacutil, simply enter gacutil with no arguments at the command line.

If you do not already have gacutil, you may need to install required packages. For .NET 1.1, gacutil is bundled with the framework. For .NET 2.0 through 3.5, you should install the Microsoft Windows SDK for .NET Framework 3.5, of which there are different downloads depending on your operating system. For .NET 4.0, you should additionally install Visual Studio 2010. If you do not want to install the SDK or Visual Studio, such as in production, you can install it on a different system and simply copy gacutil.exe.

WordWriter 3.x uses .NET 1.1 while WordWriter 4.x and higher uses .NET 2.0. You should use a version of gacutil at least as high as the .NET version required by WordWriter. Specifically, use gacutil version 1.1 or higher for WordWriter 3.x and gacutil version 2.0 or higher for WordWriter 4.x.

To uninstall WordWriter from the GAC:

1. Determine the full strong name of the WordWriter assembly:

 gacutil /lr SoftArtisans.OfficeWriter.WordWriter 

There may be multiple versions of WordWriter in the GAC. Note the full name of the assembly you want to remove; for example, SoftArtisans.OfficeWriter.WordWriter, Version=4.5.1.1641, Culture=neutral, PublicKeyToken=f593502af6ee46ae.

2. If you are using WordWriter in a web application, reset IIS to make sure the assembly is not being used. Remove the assembly from the GAC (note the use of quotes around the assembly’s full name):

 gacutil /uf "SoftArtisans.OfficeWriter.WordWriter, Version=4.5.1.1641, Culture=neutral, PublicKeyToken=f593502af6ee46ae" 

However, you may find that gacutil does not succeed due to the following error: “Assembly could not be uninstalled because it is required by Windows Installer.” In this case, follow the steps described in this Microsoft knowledge base article. In particular, open the Registry Editor, navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Assemblies\Global and remove the reference to the WordWriter assembly above. Doing so means that the Windows installer no longer attempts to remove WordWriter from the GAC during automatic uninstallation, but otherwise the uninstallation process is unaffected.

If your web application references a WordWriter assembly that has been removed from the GAC, be sure to update the reference to point to another copy of the WordWriter assembly.

WordWriter search and replace in Word textboxes

Problem

When trying to use SearchAndReplace with a Word document that has text in a Word textbox or shape, the text doesn’t get replaced.

Solution

Unfortunately, WordApplication does not recognize the shape or textbox objects and so they will not be included in the set of elements parsed by the code above. The full list of elements recognized by WordApplication is outlined in this article.

Using WordTemplate to replace text

One possible workaround is to use the WordTemplate object for text replacement instead of SearchAndReplace. When WordTemplate processes a template, it largely ignores where the merge fields are located.

This means if there is text in a shape or textbox that needs to be replaced, the original text can be placed in a merge field and then WordTemplate can populate the merge field with the new text. For example, the code below looks through a Word document for mergefields marked <> an populates them with the value “REPLACED TEXT”. Then passes the processed template to the WordApplication object.

//Start with the WordTemplate object
//Template contains merge fields named "REPLACE"
wt.Open(Page.MapPath("\templates\TextBoxTemplate.doc"));
Object[] values = {"REPLACED TEXT"};
String[] names = {"REPLACE"};
wt.SetDataSource(values, names, "DataSource");
wt.Process();
Document doc = wapp.Open(wt);
//...Other WordApplication code here...
wapp.Save(doc, Page.Response, "TextBoxTemplate.doc", False);

For more information about WordTemplate and mergefields, please refer to our WordTemplate tutorials.

How to export SSRS reports to XLSX, DOCX file formats

Problem

In Office 2007, Microsoft introduced the OOXML file formats (XLSX, XLSM), which come with benefits, such as an increase in the number of rows allowed in a file. Reporting Services reports designed for OfficeWriter allow for exports to the Office 2007 and 2003 file formats.

Solution

To export a report in a particular format, you need to explicitly save the report with the format you want to export it as:

  1. Open the report with the OfficeWriter Designer
  2. Click ‘Save As’ on the OfficeWriter Designer toolbar (for Office 2003) or ‘Save’ > ‘Save to disk’ (for Office 2007/2010)
  3. There will be three options for Reporting Definition files: Office 2007(exports to XLSX, DOCX), Office 2007 with macros (exports to XLSM, DOCM), Office 2003 and earlier (*exports to XLS, DOC)
  4. Select Office 2007 to save the RDL
  5. Publish the saved report to the server

Note: Office 2007 (XLSX, DOCX) is only available in OfficeWriter 4.0 and above. Office 2007 with macros (XLSM, DOCM) is only available in OfficeWriter 4.1 and above.

Saving ExcelWriter and WordWriter files

Problem

What options are available for saving an ExcelWriter or WordWriter generated file?

Solution

ExcelTemplate.SaveExcelApplication.SaveWordTemplate.Save, and WordApplication.Save all have the same four output options:

  • Save to disk – saves the generated file on the server
  • Save to an IO stream – streams the file to the specified IO stream or class derived from System.IO.Stream
  • Stream to the client as an attachment
  • Stream to the client as an inline file – If the user is using Internet Explorer, the file will be opened in the browser using IE’s inline browsing option. Otherwise, the file will be streamed to client.

How to use Named Styles with WordApplication

Problem

In Microsoft Word, a named style is a collection of settings for formatting attributes such as font, spacing, borders, and bullet type. A named style can be applied to a paragraph, a table, a list or a block of characters. Word comes with a large set of built-in named styles, such as Body Text and various heading styles.

While you cannot create named styles in WordWriter, you can use the WordApplication class to access named styles and apply them to a paragraph or a table. How to use named styles depends on whether you are using the WordApplication class to create a new document or to open an existing document.

This article also addresses the situation in which NullReferenceException is thrown when you try to use certain built-in named styles (see the section “Using the NamedStyle.Builtin enumeration”).

Solution

How to apply a named style

A named style is represented by the NamedStyle class. Named styles associated with a document are contained in a Styles collection, which is returned by the Document.Styles property. The Length method of the Styles collection returns the number of styles.

To retrieve a NamedStyle object, index into the Document.Styles collection by one of the following:

  1. An integer index – Document.Styles[0]
  2. The name of the style – Document.Styles[“Body Text”]
  3. A value of the NamedStyle.Builtin enumeration – Document.Styles[NamedStyle.BuiltIn.BodyText]

The most convenient method is to use the NamedStyle.Builtin enumeration, but be aware of one issue. Refer to the “Using the NamedStyle.Builtin enumeration” for more information.

To apply a named style to a paragraph, pass a NamedStyle object as parameter to the InsertParagraphBefore and InsertParagraphAfter methods (if no named style is desired, pass null in C# or Nothing in VB.NET). Alternatively, assign a NamedStyle object to the Style property of a Paragraph object.

To apply a named style to a table, assign a NamedStyle object to the Style property of a Table object.

The code sample below illustrates the use of named styles:

//--- doc is a new or existing document
//--- Applying a named style to a paragraph
NamedStyle style1 = doc.Styles[NamedStyle.BuiltIn.BodyText];
Paragraph para = doc.InsertParagraphAfter(style1);
para.InsertTextAfter("The quick brown fox jumps over the lazy dog", true);


//--- Applying a named style to a table
//--- Contemporary table style must exist in document
NamedStyle style2 = doc.Styles[NamedStyle.BuiltIn.TableContemporary];
Table myTable = doc.InsertTableAfter(2, 3);
myTable.Style = style2;

If you wish to modify or add to the formatting settings provided by a named style, you can pass a ParagraphFormatting object as a second parameter to the InsertParagraphBefore or InsertParagraphAfter methods, or assign aTableFormatting object to the Formatting property of a table.

Using named styles when creating a new document

Before you can access and use a named style with WordApplication, the style must already be stored in the document. In Word 2003, you can view the styles stored in a document (select Format, Styles and Formatting from the Word menu, then select Available Styles from the Show drop-down list on the Styles and Formatting panel). You can also view all possible styles (select Show All Styles on the Styles and Formatting panel). Normally, the number of styles stored in a document is only a subset of all possible styles. A style is not stored with the document until it is applied.

When you create a new document with the WordApplication.Create method, WordWriter automatically includes a set of styles with the newly created document. To avoid overburdening the document with unnecessary styles, the document is given a set of 28 most commonly used styles. These are given below:

  1. Normal
  2. Heading 1
  3. Heading 2
  4. Heading 3
  5. Heading 4
  6. Heading 5
  7. Heading 6
  8. Heading 7
  9. Heading 8
  10. Heading 9
  11. Default Paragraph Font
  12. Table Normal
  13. No List
  14. Block Text
  15. Body Text
  16. Body Text 2
  17. Body Text 3
  18. Body Text First Indent
  19. Body Text Indent
  20. Body Text First Indent 2
  21. Body Text Indent 2
  22. Body Text Indent 3
  23. Closing
  24. Date
  25. E-mail Signature
  26. Emphasis
  27. Envelope Address
  28. Header

Using named styles when opening an exisiting document

When you open an existing document with the WordApplication.Open method, you have access to only those named styles which are stored in the document, including custom named styles that you create before saving the document. Using custom named styles is discussed in the next section.

When you create a blank document in Word (select File, New from the menu), the document contains as many styles as are defined in the Word template on which the document is based. For example, a blank document created from the default Normal.dot template contains only a handful of basic styles. By contrast, a blank document based on the Contemporary Report.dot template has as many as 98 predefined styles.

Note that a document based on the default Normal.dot template contains fewer predefined styles than a document created with the WordApplication.Create method.

If you apply other styles to the document which are different from the default styles, the additional styles will be associated with the document and accessible to WordApplication.

Using custom named styles

In Word, you can create custom named styles. When you open an existing document containing custom styles, the custom styles are stored in the document’s Styles collection. You can access a custom style using an integer index or the style’s name.

For example, if you open an existing document containing a custom style named “My Style,” you can retrieve the NamedStyle object for “My Style” with Document.Styles[“My Style”].

Using the NamedStyle.Builtin enumeration

To get a NamedStyle object, you can use a value of the NamedStyle.Builtin enumeration as an index into the Document.Styles collection. For example, the following statement returns the the NamedStyle object for the Body Text style:

NamedStyle style;
style = Document.Styles[NamedStyle.BuiltIn.BodyText];

The NamedStyle.Builtin enumeration lists all of the possible built-in named styles in Word. The Document.Styles collection contains only the styles that are stored in the document. Typically, there are many more possible built-in styles in Word than are stored in the document.

Consequently, when you index into the Document.Styles collection using a value of the NamedStyle.Builtin enumeration, you must select a style that belongs to the collection. Otherwise, if you choose a style that does not exist in the collection, a NullReferenceException will be thrown. Unfortunately, this mistake is easy to make, because Visual Studio’s IntelliSense lists all of the values in the NamedStyle.Builtin enumeration.

For a new document created with the WordApplication.Create method, choose a NamedStyle.Builtin enumeration value corresponding to one of the 28 styles listed above. If you want to use a different style from these 28 styles, do not create a new document with WordApplication.Create. Instead, use the following workaround:

  1. In Word, create a blank document
  2. Enter some text and apply all desired styles
  3. Delete the text and save the document
  4. Open the saved document with WordApplication.Open
  5. Access the explicitly applied named style which should now be stored with the document

For an existing document, you must know a priori the named styles that exist in the document and choose the corresponding NamedStyle.Builtin enumeration values.

Unfolding a Word document with WordApplication

Problem

In the course of debugging, it can often be difficult to visualize the structure of documents as they are manipulated by WordApplication.

Solution

Our documentation has an overview of how WordApplication represents a Word document and how to insert elements using WordApplication. Additionally, there is a code sample that will produce a formatted text representation of the element hierarchy in a given document: Unfolding a Word document with WordApplication Sample.

For example, given the following document:

Our output generated by the code would look like this:

UnfoldingWordDocument

How to add page numbers or other fields with WordApplication

Problem

WordApplication does not currently have support for inserting fields other than MergeFields and Hyperlinks. You want to insert a different kind of field, such as the current page number.

Solution

WordWriter has a MergeField class and a Hyperlink class which allow you to programmatically insert those fields. However, those are currently the only two fields which are included in the WordWriter API. In order to insert a field such as a page number into a newly generated document in WordApplication, you must first create a document with Microsoft Word and copy the field from there.

Inserting Footers with Fields

If you wish to create a footer which includes a field such as the page number, you must first create a document in Microsoft Word. Add all the text, fields, and formatting that you wish to appear in the final document to this file. For the purposes of this article, this file will be called ‘footer.doc’.*

In order to use your newly created footer, you must open the document in your WordApplication and copy the footer into the document you are generating programmatically:

//Create the document you want to insert a footer into
Document doc = wa.Create();


//Or open an existing file, instead of creating one
//Document doc = wa.Open("myFile.doc");


//Open the document with the footer you want to copy
Document footerDoc = wa.Open(Page.MapPath("footer.doc"));


//Get the footers for both documents
Element footerSource = footerDoc.Sections[0].get_Footer(Section.HeaderFooterType.All);
Element footerDestination = doc.Sections[0].get_Footer(Section.HeaderFooterType.All);

//Insert the footer into the destination document
footerDestination.InsertAfter(footerSource);
In this way, you can copy the footer into a newly generated document or one that was opened from a different file. For more information about retrieving footers or headers and inserting them as Elements, see the documentation for the Section and the Element classes.

Inserting Headers with Fields

Copying the header is very similar to copying the footer, except that you would insert the header Element instead of the footer. So if you have a document called ‘header.doc’ that you wish to copy the header from, you can say:

//Create the document you want to insert a header into
Document doc = wa.Create();


//Or open an existing file, instead of creating one
//Document doc = wa.Open("myFile.doc");


//Open the document with the header you want to copy
Document headerDoc = wa.Open(Page.MapPath("header.doc"));


//Get the headers for both documents
Element headerSource = footerDoc.Sections[0].get_Header(Section.HeaderFooterType.All);
Element headerDest = doc.Sections[0].get_Header(Section.HeaderFooterType.All);


//Insert the header into the document
headerDest.InsertAfter(headerSource);

Inserting Fields into the Body of a Document

If you instead want to insert a field into the body of the document along with programmatically generated content, you can retrieve only the Field Element from a pregenerated file. For example, if you want to insert a ‘Date’ field into the body of a document, you must first create a new file in Microsoft Word. Add a Date field to the body of this new document by going to Insert->Field and choosing Date. Save the document. For the purposes of this article, the file will be called ‘datefield.doc’.

In your WordApplication, when you want to insert the field, you will open the datefield.doc document, retrieve the field, and insert it into your own document:

//Open the document with the date field in it
Document fieldDoc = wa.Open(Page.MapPath("datefield.doc"));


//Get the date field from the body of the document. We use an index of 0
//because it is the first (and only) field element in the document.
Element dateField = fieldDoc.get_Elements(Element.Type.Field)[0];


//Insert the date field into the body of another document (called 'doc').
doc.InsertAfter(dateField);

In this way, you can programmatically add Microsoft Word fields to a newly generated document. For more information about how to specify what type of Element you want to retrieve from the document, see the documentation for the Elements property of the Element class and refer to the different types of Elements that you can ask for.