Jeremiah Reed
Jeremiah Reed

Reputation: 83

.NET MS Word Interop - How to write data to tables quickly

I have a Word document that is used as a template (but is not a Word template, just a .doc file) with tables in them that I need to populate with data. I am not having trouble populating the tables with data or writing anything that I need. The problem I am having is that it is taking forever to write the data because Word appears to be typing the text out in real-time.

The only possible solution I have seen online is to set.Visible = False, but I am doing that and it takes about 10 minutes to write 1000 rows of data.

I am upgrading a report application that was able to do the same thing in 5 seconds but it was written in VB6, so I can't imagine that it can't go just as fast in .NET.

Here's the setup for the code example below: I have the data in a .NET DataTable with a bookmark name and a value. Multiple occurrences of the bookmark name identify which table these should go into. All of that is irrelevant because it all works, unless I am doing it in a way that causes .TypeText() to go really slow. I even did some debugging and just the .TypeText() appears to take 1 whole second each time, which makes 1000 rows take anywhere from 10-15 minutes to write out.

    Dim WordApp As New Word.Application()
    WordApp.Documents.Open("C:\Report_Template.doc", [ReadOnly]:=True)

    With WordApp
        Try
            .Visible = False

            .ActiveDocument.SaveAs2("C:\Report.doc")
            .ActiveWindow.View.ReadingLayout = False

            With .Selection
                Dim Bookmark As String

                For Each BookmarkRow As DataRow In MyDataTable

                    Bookmark = BookmarkRow("Bookmark")

                    'create a sub datatable of each distinct bookmark name
                    Dim BookmarkView As New DataView(dtItemizedValues)
                    BookmarkView.RowFilter = "BOOKMARK = '" & Bookmark & "'"
                    Dim BookmarkData As DataTable = BookmarkView.ToTable()

                    'go to the bookmark
                    .GoTo(Word.WdGoToItem.wdGoToBookmark, , , Bookmark)

                    'move to the table for this section
                    .GoTo(Word.WdGoToItem.wdGoToTable, Word.WdGoToDirection.wdGoToNext)

                    'loop through rows
                    For Each Row As DataRow In BookmarkData.Rows
                        If .Text.Length > 0 Then
                            .SelectCell()
                            .Cut()
                        End If

                        .TypeText(Text:=Row("Value"))

                        'move to next row
                        .Move(Word.WdUnits.wdRow)
                    Next 'row
                Next 'bookmark


            End With 'with .selection

            .ActiveDocument.Close(SaveChanges:=True)
        Catch ex As Exception
            .ActiveDocument.Close()
        Finally
            WordApp.Quit(False)
        End Try
    End With 'with .wordapp

Upvotes: 0

Views: 1722

Answers (1)

Cindy Meister
Cindy Meister

Reputation: 25673

I wrote an article about this, many years ago... Constructing a table, cell-by-cell or row-by-row and filling it with data is slow. And the longer the table gets, the slower things become due to how Word repaginates.

The essential steps for achieving top efficiency are:

  • concatenate all the data in a character-delimited string
  • assign that string to a Range object in Word
  • use ConvertToTable to turn the string into a table

Simple sample:

//Insert table at end of currently active document
Sub ConvertTextStringToTable()
    Dim doc As Word.Document = Word.Application.ActiveDocument
    Dim rng As Word.Range = doc.Content
    Dim data As String
    data = "one" & vbTab & "two" & vbTab & "three" & vbCr & _
           "1" & vbTab & "2" & vbTab & "3" & vbCr

    rng.Collapse(Word.WdCollapseDirection.wdCollapseEnd)
    rng.Text = data
    Dim tbl as Word.Table = rng.ConvertToTable(vbTab)
End Sub

Upvotes: 3

Related Questions