How to Export Data to Microsoft Word with the LightSwitch HTML Client – Part 2 (Elizabeth Maher)

How to Export Data to Microsoft Word with the LightSwitch HTML Client – Part 2 (Elizabeth Maher)

  • Comments 2

The last article covered how to add a web controller to the LightSwitch server project to create and return a generated report in a Word document using the Open XML SDK for Office. However, the report we created is not one that would be considered pleasing to the eye. In this article, we will fix that.   We will also cover how to call the web controller from a client page in a LightSwitch project.

Adding Styles

Documents created through OpenXml do not have any styling by default. These styles must be added. Below are two functions that create and return the simplified versions of the Title and Heading 1 styles seen in a normal Word document.

C#:

Style GetTitleStyle()
{
            Style titleStyle = new Style()
            {
                Type = StyleValues.Paragraph,
                StyleId = "Title",
                CustomStyle = true
            };
            titleStyle.Append(
                 new StyleName() { Val = "Title" },
                 new StyleRunProperties(
                      new Color() { Val = "2E74B5" },
                      new FontSize() { Val = "56" }
                       )
                );
            return titleStyle;
}
Style GetHeading1Style()
{
            Style heading1Style = new Style()
            {
                Type = StyleValues.Paragraph,
                StyleId = "Heading1"
            };
            heading1Style.Append(
                new StyleName() { Val = "heading 1" },
                new StyleParagraphProperties(
                     new KeepNext(),
                     new KeepLines(),
                     new SpacingBetweenLines() { Before = "240", After = "0" }
                     ),
                new StyleRunProperties(
                    new Color() { Val = "2E74B5" },
                    new FontSize() { Val = "32" }
                    )
                );

            return heading1Style;
}

VB:

Private Function GetTitleStyle() As Style
        Dim titleStyle As New Style() With {.Type = StyleValues.Paragraph, .StyleId = "Title",
                                            .CustomStyle = True}
        titleStyle.Append( _
            New StyleName() With {.Val = "Title"},
            New StyleRunProperties( _
                New Color() With {.Val = "2E74B5"},
                New FontSize() With {.Val = "56"}
               )
            )
        Return titleStyle
End Function

 Private Function GetHeading1Style() As Style
        Dim heading1Style As New Style With {.Type = StyleValues.Paragraph,
                                             .StyleId = "Heading1"}
        heading1Style.Append( _
            New StyleName() With {.Val = "Heading 1"},
            New StyleParagraphProperties( _
                New KeepNext(),
                New KeepLines(),
                New SpacingBetweenLines() With {.Before = "240", .After = "0"}
                ),
            New StyleRunProperties( _
                New Color() With {.Val = "2E74B5"},
                New FontSize() With {.Val = "32"}
               )
        )
        Return heading1Style
End Function

Below is a modified version of our CreateDetailedWordDoc function from the last article. The function iterates through all the properties and values of an entity as represented by a Dictionary object. The styles must be added to the document style definitions. The styles must then be then applied to the properties for that paragraph.  I have highlighted the new code.

C#:

 private MemoryStream CreateDetailedWordDoc(string title, Dictionary<string, object> entityData)
{
            MemoryStream s = new MemoryStream();

            //Create word document
            using (WordprocessingDocument wordDocument = 
                WordprocessingDocument.Create(s, WordprocessingDocumentType.Document, true))
            {
                //Create the main document part, which is the part that holds the text.
                wordDocument.AddMainDocumentPart();
                wordDocument.MainDocumentPart.Document = new Document(new Body());
                Body body = wordDocument.MainDocumentPart.Document.Body;

                // Get the Styles part for this document.
                if (wordDocument.MainDocumentPart.StyleDefinitionsPart == null)
                {
                    new Styles().Save(
                        wordDocument.MainDocumentPart.AddNewPart<StyleDefinitionsPart>());
                }
                wordDocument.MainDocumentPart.StyleDefinitionsPart.Styles.Append(
                    GetTitleStyle());
                wordDocument.MainDocumentPart.StyleDefinitionsPart.Styles.Append(
                    GetHeading1Style());
     
               //Add Title to Document
                body.Append(
                    new Paragraph(
                      new ParagraphProperties(new ParagraphStyleId() { Val = "Title" }),
                      new Run(new Text(title))
                     )
               );

                //Add Each property
                foreach (var entry in entityData)
                {
                    body.Append(
                        new Paragraph(
                            new ParagraphProperties(new ParagraphStyleId() { Val = "Heading1" }),
                            new Run(new Text(entry.Key))
                        ),
                        new Paragraph(
                            new Run(new Text(entry.Value.ToString()))
                        ),
                        new Paragraph(
                            new Run(new Text(""))
                        )
                    );
                }
              
                wordDocument.MainDocumentPart.Document.Save();
                wordDocument.Close();
            }

            return s;
}

VB:

 Private Function CreateDetailedWordDoc(title As String, entityData _
                                           As Dictionary(Of String, Object)) As MemoryStream
        Dim s As New MemoryStream()

        'Create Word document
        Using wordDocument As WordprocessingDocument =
            WordprocessingDocument.Create(s, WordprocessingDocumentType.Document, True)

            'Create the main document part,
            ' which is the part that holds the text.
            wordDocument.AddMainDocumentPart()
            wordDocument.MainDocumentPart.Document = New Document(New Body())
            Dim docBody As Body = wordDocument.MainDocumentPart.Document.Body

            'Get the Styles part for this document
            ' and add our custome styles
            If wordDocument.MainDocumentPart.StyleDefinitionsPart Is Nothing Then
                Call New Styles().Save(
                    wordDocument.MainDocumentPart.AddNewPart(Of StyleDefinitionsPart))
            End If
            wordDocument.MainDocumentPart.StyleDefinitionsPart.Styles.Append(
                GetTitleStyle())
            wordDocument.MainDocumentPart.StyleDefinitionsPart.Styles.Append(
                GetHeading1Style())

            'Add Title to Document
            docBody.Append(New Paragraph( _
                           New ParagraphProperties(
                               New ParagraphStyleId() With {.Val = "Title"}
                               ),
                           New Run(New Text(title)))
                       )

            'Add Each property
            For Each entry In entityData
                docBody.Append( _
                    New Paragraph( _
                        New ParagraphProperties(
                            New ParagraphStyleId() With {.Val = "Heading1"}
                            ),
                        New Run(New Text(entry.Key))),
                    New Paragraph(New Run(New Text(entry.Value.ToString()))),
                    New Paragraph(New Run(New Text("")))
                )
            Next
        End Using

        Return s
End Function

Try it out

Try debugging and typing http://localhost:[debuggingPort]/reports/ExportToWord/Events/1 in the Internet Explorer address bar and you will see a much prettier version of our detailed report.

clip_image002

The code above is a quick way add a style to document programmatically. If you need more elaborate styling in the generated word document, I suggest using the Open XML SDK 2.5 Productivity Tool (part of the Open Xml SDK download). The reflect code functionality of the Productivity Tool will show you generated code or a xml document for all of the styles of an opened file. Below is an example showing the generated code for the Title style used in a document I had available.

clip_image004

OpenXml also provides a way to use the Styles.Load method to load styles described from an xml document. This method allows separation between styling and content generation.

Launch Report from the Client

Next, we need a way for our users to easily launch the generated report. To do this, we need create a button and then open a window to the url that will send back the generated report. Below you can see that I have added a button, called GetReport, to the view details page for our EventSessions entity.

clip_image006

Once that is done, the execute code can open the correct url for the report.

myapp.ViewEventSession.GetReport_execute = function (screen) {
    window.open("../reports/ExportToWord/Events/" + screen.EventSession.Id);
};

Wrap Up

And that’s it. We have added the ability for our user to export data into a generated a Word document by simply clicking a button.

In the next article in this series , we will use all the techniques from the first two articles to generate a report that summarizes all the EventSessions in our application.

-Elizabeth Maher, Senior SDET, Cloud Business Apps Team

Leave a Comment
  • Please add 6 and 6 and type the answer here:
  • Post
  • Does this work with AzureWebSites?

    I published an app  to Azure -but  it indicated that it cannot load file assembly  DocumentFormat.OpenXml

    Thanks

  • Follow up to  below:

    The reference for DocumentFormat.OpenXml must be set to copy local. It then copies to AzureWebSites and then works

Page 1 of 1 (2 items)