Write DataTable to an MS Word Table Efficiently with C# using a Dynamic Type

This is a C# adaptation of the code I wrote to write a datatable to a Microsoft Word document table for vb.net . But that doesn’t really begin to tell the story here. In vb.net we have been accustomed to being allowed to leave parameters empty when automating the creation of a table in Microsoft Word. C# has not permitted me that luxury which to be honest is probably a better code practice. So prepare to meet the Type.Missing object! In addition the default item that we learned to love/hate in Visual Basic for Applications (VBA) code years ago also is not used in C#. Finally in declaring the range object for the table it became an opportunity to use the new dynamic reference type keyword, which was designed for such situations. Check out this video on the subject which is quite excellent.

http://channel9.msdn.com/Shows/Going+Deep/Inside-C-40-dynamic-type-optional-parameters-more-COM-friendly/player?w=512&h=288

For these reasons you will see key differences between the two sets of code. Don’t forget to import Microsoft Word as a COM reference and do your import statements. As always feel free to comment or email. Have a great day!

using Office = Microsoft.Office.Core;
using Word = Microsoft.Office.Interop.Word;

public void CreateWordTableWithDataTable(DataTable dt)
        {
            int RowCount = dt.Rows.Count; int ColumnCount = dt.Columns.Count;
            Object[,] DataArray = new object[RowCount + 1, ColumnCount + 1];
            //int RowCount = 0; int ColumnCount = 0;
            int r = 0;
            for (int c = 0; c <= ColumnCount – 1; c++)
            {
                DataArray[r, c] = dt.Columns[c].ColumnName;
                for (r = 0; r <= RowCount – 1; r++)
                {
                    DataArray[r, c] = dt.Rows[r][c];
                } //end row loop
            } //end column loop

            Word.Document oDoc = new Word.Document();
            oDoc.Application.Visible = true;
            oDoc.PageSetup.Orientation = Word.WdOrientation.wdOrientLandscape;
           
            dynamic oRange = oDoc.Content.Application.Selection.Range;
            String oTemp = “”;
            for (r = 0; r <= RowCount – 1; r++)
            {
                for (int c = 0; c <= ColumnCount – 1; c++)
                {
                    oTemp = oTemp + DataArray[r, c] + “\t”;
                  
                }
            }

oRange.Text = oTemp;
           
object Separator = Word.WdTableFieldSeparator.wdSeparateByTabs;
object Format = Word.WdTableFormat.wdTableFormatWeb1;
object ApplyBorders = true;
object AutoFit = true;

object AutoFitBehavior = Word.WdAutoFitBehavior.wdAutoFitContent;
            oRange.ConvertToTable(ref Separator,
        ref RowCount, ref ColumnCount, Type.Missing, ref Format,
        ref ApplyBorders, Type.Missing, Type.Missing, Type.Missing,
         Type.Missing, Type.Missing, Type.Missing,
         Type.Missing, ref AutoFit, ref AutoFitBehavior,
         Type.Missing);
           
            oRange.Select();
            oDoc.Application.Selection.Tables[1].Select();
            oDoc.Application.Selection.Tables[1].Rows.AllowBreakAcrossPages = 0;
            oDoc.Application.Selection.Tables[1].Rows.Alignment = 0;
            oDoc.Application.Selection.Tables[1].Rows[1].Select();
            oDoc.Application.Selection.InsertRowsAbove(1);
            oDoc.Application.Selection.Tables[1].Rows[1].Select();

            //gotta do the header row manually
            for (int c = 0; c <= ColumnCount – 1; c++)
            {
               oDoc.Application.Selection.Tables[1].Cell(1, c + 1).Range.Text = dt.Columns[c].ColumnName;
            }

            oDoc.Application.Selection.Tables[1].Rows[1].Select();
            oDoc.Application.Selection.Cells.VerticalAlignment = Word.WdCellVerticalAlignment.wdCellAlignVerticalCenter;
                      
                    }

Facebook

Advertisements

, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

  1. #1 by Luis Molina on May 22, 2018 - 3:57 pm

    Muchas muchas gracias, gracias a tu código pude hacer una generación de un informe en Word!
    Fue de mucha ayuda. le hice unas cuantas modificaciones pero el código base me sirvió muchísimo!
    Muy agradecido.

  2. #2 by RICARDO LOPES on November 25, 2018 - 10:21 am

    Excellent code Kelly!
    I have created a VBA version of such code. It does not address the ColumnName Heading feature shown in your code. This VBA code assumes that the table has Column Headings, but they are blank. If needed, the additional code for the Headings must be added.

    Public Sub KellyChronicle_ArrayTable()
    Dim lRows As Long
    Dim lColumns As Long
    Dim oRange As Range
    Dim dsreport As Document
    Dim oDoc As Document
    Dim c As Long
    Dim r As Long
    Dim oTemp As String
    ‘creating the array that will hold our data
    Dim DataArray() As Variant
    ‘Table must be created manually in Document1
    ‘Replace Documents name to match your case
    Set dsreport = Documents(“Document1”)
    Set oDoc = Documents(“Document2”)

    lRows = dsreport.Tables.Item(1).rows.Count
    lColumns = dsreport.Tables.Item(1).columns.Count

    ReDim DataArray(0 To lRows – 1, 0 To lColumns – 1)

    ‘writing the data to the array
    For c = 0 To lColumns – 1
    For r = 0 To lRows – 1
    DataArray(r, c) = Split(Replace(dsreport.Tables(1).Cell(r + 1, c + 1).Range.Text, Chr(7), vbNullString), Chr(13))(0)
    Next
    Next
    ‘creating a range at the Word Document insertion point
    Set oRange = oDoc.Content.Application.Selection.Range
    ‘creating a string to hold what is in our array
    For r = 0 To lRows – 1
    For c = 0 To lColumns – 1
    If Not (r = lRows – 1 And c = lColumns – 1) Then
    oTemp = oTemp & DataArray(r, c) & vbTab
    Else
    oTemp = oTemp & DataArray(r, c)
    End If
    Next
    Next
    ‘writing the text to our document. It is not a table yet.
    oRange.Text = oTemp
    ‘convert it to a table using vba and you are done!
    oRange.ConvertToTable Separator:=wdSeparateByTabs, NumRows:=lRows, NumColumns:=lColumns, AutoFitBehavior:=wdAutoFitContent
    End Sub

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: