Category Archives: OfficeWriter

How to use merge fields with a bar code format

Problem

You create a Word document containing a merge field formatted with a Bar Code font, such as Code 39. You use the WordTemplate class to process the document. However, in the generated document, the merge field is populated with text in the Times New Roman font. The problem is illustrated in the figures below:

Merge field
Formatted merge field
Output

Solution

A bar code field must begin and end with a delimiter character. For the Code 39 font, this required delimiter is represented in human-readable text as the * character.

When you create the merge field in a Word document, insert the * character into the merge field using merge field switches. Then you can format the merge field with a bar code font. The procedure is as follows:

1. From the Word menu, select Insert, Field.

2. In the dialog box, select MergeField and fill in the fields as illustrated in the figure below. Use an appropriate name for Field name.

After you close the dialog box, the merge field should appear as follows:

3. Select the entire merge field and format it with a bar code font, such as Code 39.

In the generated document, the merge field should now contain the text in the bar code font. The following figure shows the results for the string *0123456789*.

To see that this does in fact represent the correct string, you can select the text and choose a different, readable font, or copy and paste the text into a text editor.

How to apply auto filters with ExcelApplication

Details

Auto filters are an Excel feature that can be applied to a column of data that allows users to select what rows of data they want visible for a given area on a worksheet.

The ability to apply auto filters programmatically with ExcelApplication in XLSX and XLSM files was added in OfficeWriter 8.3. This post covers how to add auto filters with the ExcelWriter API.

Solution

  1. Define the Area that the auto filter will be applied to.
  2. Get a handle on the AutoFilter object for the Worksheet that will have the auto filter.
  3. Set the worksheet’s AutoFilter.Area to the area that was defined earlier.

Here is the code:

Area filter_area = ws.PopulatedCells; //Returns a continuous area of all the populated cells
AutoFilter filter = ws.AutoFilter;
filter.Area = filter_area;

Here is the code in a single line:
ws.AutoFilter.Area = ws.CreateArea("A1:H1");

Additional Resources

To remove the auto filter from a worksheet, use AutoFilter.Clear():
ws.AutoFilter.Clear();
A few things to bear in mind:

  • A worksheet can only contain one area with auto filters. If you set Worksheet.AutoFilter.Area, you will overwrite any existing auto filters.
  • You must specify the entire area that you want to apply the filters to. ExcelWriter will not automatically detect blank rows and columns. We recommend Worksheet.PopulatedCells for getting a handle on all the populated cells in a worksheet.

How to use ASP.NET MVC with OfficeWriter

Problem

A number of customers have asked about support for ASP.NET MVC. With the introduction of ASP.NET MVC, the method to send OfficeWriter-generated files to the user requires a few more lines of code. In ASP.NET WebForms, OfficeWriter can write directly to the HttpResponse stream via the Save method, allowing for a one-line implementation. In MVC, all the functions from a Controller return an ActionResult, and it requires a different approach to return the file to the user.

Solution

To facilitate file downloads, we need an ActionResult to return the file generated by OfficeWriter. For use in ASP.NET MVC, we need to return our file via an ActionResult for the Controller’s action; the specific type used below for doing that is the FileStreamResult by using OfficeWriter to get a stream of the file.

The overview of what we need to do is summarized in the algorithm below:

  1. Create the appropriate OfficeWriter object.
  2. Get the data into the file, using the various data binding methods like ExcelTemplate.BindData and WordTemplate.SetDataSource.
  3. Process the file.
  4. Save the file to an in-memory Stream (using MemoryStream); check out ExcelTemplate.SaveExcelApplication.SaveWordTemplate.Save, and WordApplication.Save.
  5. Return the FileStreamResult, set to use the in-memory Stream.

The following is a C# sample that uses ExcelTemplate. This general approach also works for ExcelApplication, WordTemplate, and WordApplication.

public ActionResult Download()
{
if (ModelState.IsValid)
{
var excelTemplate = new ExcelTemplate();
excelTemplate.Open(Server.MapPath("~/Templates/Download_Template.xlsx"));


// get the data into the file
excelTemplate.Process();
var stream = new MemoryStream();
excelTemplate.Save(stream);


// make sure to reset the position because we will be reading it again
stream.Position = 0;
var actionResult = new FileStreamResult( stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" );
actionResult.FileDownloadName = "Download.xlsx"; return actionResult;
} return View();
}

The above code would be placed inside a Controller for the Download action. When this action is activated, a file download prompt will appear for the user with the file name that was given to the FileStreamResult.

How to create a dual axis chart from bar charts

Problem

With the ExcelApplication object, it is possible to create and manipulate charts, including bar charts with series on both the primary and secondary axes. In this example, we will cover how to use OfficeWriter to create a dual axis bar chart.

Note: The ExcelApplication object is only available in OfficeWriter Enterprise Edition (EE).

Solution

This example assumes that you are familiar with creating charts with ExcelApplication. If you’re not, we recommend that you check out Charts in ExcelApplication.

Let’s start with given data in worksheet Sheet1:

The following code snippet creates a bar chart with two series from that data:

Worksheet wkst = wb.Worksheets["Sheet1"];
Anchor anchr = wkst.CreateAnchor(5, 5, 0, 0);


//Create the chart
Chart chrt = wkst.Charts.CreateChart(ChartType.Bar.Clustered, anchr);


//Set the category axis data for the chart
chrt.SeriesCollection.CategoryData = "A2:A4";


//Create a cluster bar series on the primary axis
Series series1 = chrt.SeriesCollection.CreateSeries("B2:B4", ChartType.Bar.Clustered, AxisType.Primary);


//Create a cluster bar series on the secondary axis
Series series2 = chrt.SeriesCollection.CreateSeries("C2:C4", ChartType.Bar.Clustered, AxisType.Secondary);

If you are working with an existing chart, you can set the Series.AxisType property to AxisType.Secondary.

 series2.AxisType = AxisType.Secondary 
This will produce a chart that looks like the following:

The reason why only one series appears on the chart is because of an issue with how Excel displays bar and column charts on two axes.

To get around this, you should pad your data with zeroed values which act as placeholders for the bar or column chart series. Peltier Tech has a blog post with details on how to show a Column Chart on Two Axes. These principles also apply to bar charts.

This workaround can also be applied to OfficeWriter charts.

Dual Axis Chart Workaround

1. Pad the data to include the zeroed columns.

2. Add code for the place holder series on the primary and secondary axes


//Create a cluster bar series on the primary axis
Series series1 = chrt.SeriesCollection.CreateSeries("B2:B4", ChartType.Bar.Clustered, AxisType.Primary);


//Create the zeroed placeholder series for the primary axis
Series series2_pad = chrt.SeriesCollection.CreateSeries("C2:C4", ChartType.Bar.Clustered, AxisType.Primary);


//Create the zeroed placeholder series for the secondary axis
Series series1_pad = chrt.SeriesCollection.CreateSeries("D2:D4", ChartType.Bar.Clustered, AxisType.Secondary);


//Create a cluster bar series on the secondary axis
Series series2 = chrt.SeriesCollection.CreateSeries("E2:E4", ChartType.Bar.Clustered, AxisType.Secondary);

3. Add code to hide the legend entries for the placeholder series:
//Hide the placeholder legend entries
series2_pad.ShowLegendEntry = false;
series1_pad.ShowLegendEntry = false;

The final chart should display both series correctly on the separate axes:

Note: The change in color is because there are technically 4 series in the chart and Excel’s automatic coloring reflects this.

How to format alternating color rows with ExcelApplication

Problem

A common way to display data in Excel is to alternate the background color of every other row when displaying a large table of data. With ExcelWriter there are multiple ways to accomplish this. This post covers some possible ways to apply alternating row colors with ExcelApplication.

There is another post that discusses how to do this with ExcelTemplate.

Solution

In versions of ExcelApplication prior to 6.5.1, the only way to set alternating background colors on a table was to loop over all the rows you wanted to format and set their background colors one at a time. This can take a long time for large amounts of data, and requires quite a bit of code. With the introduction of the ConditionalFormat object in ExcelWriter 6.5.1, alternating row colors in a Range with the ExcelApplication object is much simpler and faster.

The first step is to choose colors for the odd and even rows. In this example I’ll color even-numbered rows a light blue and odd-numbered rows white. You can use any colors you like, as long as they exist in the Palette or you add them yourself.

The second step is to create the ConditionalFormat object and the conditions within it. Each Condition has a comparison rule that gets set up in the constructor and a Style object that will be applied to each cell for which that rule is true. To alternate row colors we need two Conditions: one that will format the odd-numbered rows and one for the even-numbered rows.

To do this we use the FormulaEvaluation comparison type and create formulas that evaluate to true depending on the numbering of the row. The MOD() function returns the remainder left after dividing its first argument by its second, and the ROW() function returns the 1-indexed number of the current cell’s row. Thus, MOD(ROW(), 2)=1 will be true for all odd-numbered cells, and MOD(ROW(), 2)=0 will be true for odd-numbered cells.

After creating the conditions, we change the formatting of the Style objects associated with them. For this example all we’ll do is change the background color, but we could apply any formatting that can be set with through the Style object. As in the example below, we suggest that you modify the existing Condition.Style object rather than creating a new Style object and setting Condition.Style to it, as some attributes are not preserved properly with the second method.

The final step is to create the Range this formatting should be applied to and associate the ConditionalFormat with the Range. The following code illustrates these steps and produces the screenshot below.


// Create the colors we'll use on alternating rows. In Excel you can only
// use colors in the Palette, so we need to create a Palette object and use
// that to get the colors.
Palette p = wb.Palette;
Color evenColor = p.GetClosestColor(153, 204, 255);
Color oddColor = p.GetClosestColor(255, 255, 255);


// Create the conditional format and its conditions. Each condition
// has a formula that can evaluate to true or false.
ConditionalFormat oddEvenColors = wb.CreateConditionalFormat();
Condition evenRows;
evenRows = oddEvenColors.CreateCondition(Condition.Comparison.FormulaEvaluation, "=MOD(ROW(), 2)=0");
Condition oddRows; oddRows = oddEvenColors.CreateCondition(Condition.Comparison.FormulaEvaluation, "=MOD(ROW(), 2)=1");


// Change the background color for each condition. This is what will change
// for the cells where the condition is true.
evenRows.Style.BackgroundColor = evenColor;
oddRows.Style.BackgroundColor = oddColor;


// Create the range we want to format and set the formatting.
Range toFormat = ws.CreateRange("A1:F10");
toFormat.SetConditionalFormat(oddEvenColors);

Note that the conditional formatting is applied rather than set. This means that only the differences between any existing styles and the conditional formatting will take effect. For example, if some of the cells in the range had a border or had changed the font size, those changes will not be affected when we change the background color. See our documentation for more on setting and applying styles.

How to autofit all cells in a workbook when using the ExcelTemplate object

Problem

When using the ExcelTemplate object to populate a spreadsheet with data, you may want to AutoFit the row heights or column widths to better display the data in the cells. The AutoFit needs to be done after all the data has been populated.

ExcelTemplate is a small, light-weight object model that is designed to populate data very quickly. ExcelTemplate does not provide AutoFit functionality, because that would require parsing the entire spreadsheet and creating objects for every single cell, the way the ExcelApplication object does with its much larger object model.

Solution

One solution is to pass the workbook to the ExcelApplication object after it has been populated with data, and then perform the AutoFit (using ColumnProperties.AutoFitWidth or RowProperties.AutoFitHeight). However, this can have an impact on performance, particularly if the workbook contains a lot of data.

If you want to avoid reopening the workbook on the server with the ExcelApplication object, another solution is to use a macro that will run when the user opens the file on the client machine. The following VBA code can be placed in your template spreadsheet to AutoFit all of the cells in a workbook. The code should be placed in the ThisWorkbook object in the VBA Project for the spreadsheet.


Private Sub Workbook_Open()
Dim ws As Worksheet
For Each ws In Me.Worksheets ws.Cells.Columns.AutoFit ws.Cells.Rows.AutoFit Next End Sub

How to hide a worksheet with ExcelApplication

Problem

A worksheet may contain proprietary data or algorithms that developers wish to hide from end-users. Different methods of hiding your data exist, but some methods are more secure than others.

Solution

An ExcelWriter workheet can be hidden by setting the Worksheet.Visibility property to Worksheet.SheetVisibility.Hidden. However, the worksheet can be un-hidden by users in Excel.

To make the worksheet more hidden, set Worksheet.Visibility to Worksheet.SheetVisibility.VeryHidden, in which case the worksheet will remain hidden unless the end-user writes a new VBA macro to unhide it.

Therefore, to keep a worksheet hidden, the developer must prevent end-users from creating new macros for the workbook as well. To do this, open the workbook’s macro editor and add a password to lock the project.

Password Protecting VBA in Excel 2007/2010

  1. Go to the Developer tab in the ribbon
  2. Go to Visual Basic
  3. Go to Tools > VBAProject Properties > Protection
  4. Check Lock project for viewing and add a password

Password Protecting VBA in Excel 2003

  1. Go to Tools > Macro > Macros
  2. Edit an existing macro
  3. In the macro editor, right-click the VBA project.
  4. Go to VBA Project Properties > Protection.
  5. Check the checkbox and add a password.

This will make it impossible for the user to look at your existing macros or to add a macro to unhide a sheet.

How to hide rows in a Pivot Table

Problem

ExcelWriter fully preserves existing pivot tables however the .NET implementation of the ExcelApplication object does not offer any support for manipulating the pivot tables. Since there is no way to programmatically hide pivot table rows with the ExcelApplication object this must be done in VBA.

Solution

In order to hide rows in your pivot table, you can include the following VBA which will execute when the user opens the spreadsheet in Excel.

Due to the sequence in which events are fired it is necessary to explicitly refresh the data in a pivot table in the Workbook_Open event instead of relying on the “Refresh on Open” Option in the pivot table options.

Disabling the option in Excel and refreshing the data in Workbook_Open() guarantees that the data has been refreshed after which you can the hide rows:

Private Sub Workbook_Open()
Worksheets(1).PivotTables("Pivot1").PivotCache.Refresh
Worksheets(1).PivotTables("Pivot1").PivotFields("Field1").PivotItems("Row1").Visible = False Worksheets(1).PivotTables("Pivot1").PivotFields("Field1").PivotItems("Row2").Visible = False
End Sub

Working with Reporting Services in SharePoint integration mode

Problem

From version 3.9.2 and above support has been added to OfficeWriter Designer to work seamlessly with Reporting Services running in SharePoint integrated mode. All operations such as retrieve, publish and view reports are supported.

This feature is available in the client-side OfficeWriter Designer for Excel and Word. The server-side components of OfficeWriter require no special modification to work with Reporting Services running in SharePoint integrated mode with one exception, outlined below. We recommend always using matching versions of the designer and the server-side installation of OfficeWriter.

There are a few things to note when using the Designer in SharePoint integrated mode that differ from regular use, which are outlined in this post.

Solution

The Designer

When publishing or retrieving a report using the Designer, enter your SharePoint root site in the server URL textbox, like in the image below. Enter the address without the additional /ReportServer usually added for Reporting Services not running in integrated mode:

Please Note: Adding /ReportServer after the SharePoint site address will cause the operation to fail with the following error message:

The operation is not supported on a report server that is configured to run in SharePoint integrated mode.

For more information about using the OfficeWriter Designer, refer to our documentation on the OfficeWriter SSRS Integration.

Server-side

In SQL Server Reporting Services 2012, Microsoft changed the structure of SharePoint integrated mode for SharePoint 2010 and above. Essentially, SSRS is run through SharePoint service applications, rather than through the traditional Reporting Services configuration. All configuration settings are stored in a database, rather than config files.  This affects how OfficeWriter’s server-side renderer is installed in SSRS integrated with SharePoint.

Starting in 8.5.1, OfficeWriter can install against SSRS 2012 with SharePoint 2010 or 2013. During installation, the user will be prompted to select their SSRS instance as well as the SharePoint service application to install the renderer to.

There are no other changes to how OfficeWriter behaves in SSRS and SharePoint integrated mode.

Running VBA macros in Internet Explorer

Problem

Some VBA macros in a spreadsheet processed by ExcelWriter or WordWriter fail to execute when the file is opened in Internet Explorer. However, if the file is saved to the local filesystem and opened afterwards in Excel or Word, the macro works fine.

Solution

This issue is with MS Office and Internet Explorer, not with OfficeWriter. OfficeWriter preserves all VBA macros when processing a spreadsheet or document. However, not all VBA will execute in the Excel or Word browser plug-ins. In order to guarantee that all your macros will run in your OfficeWriter-generated files, it is recommended to use the Save option that will open the file in a separate Excel or Word window rather than in the browser.

For more information, see this article: Some Macro Commands Are Not Run in MS Internet Explorer.

Code samples

To make sure that your OfficeWriter-generated files are opened in Excel or Word instead of the browser, specify ‘false’ when using the Save method:
xlt.Save(Page.Response, "WorkbookWithMacros_out.xlsm", false); //ExcelTemplate
xla.Save(workbook, Page.Response, "WorkbookWithMacros_out.xlsm", false); //ExcelApplication
wt.Save(Page.Response, "DocWithMacros_out.docm", false); //WordTemplate
wapp.Save(document, Page.Response, "DocWithMacros_out.doc", false); //WordApplication