Click here to Skip to main content
15,886,657 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
I've few MS word documents (with tables and all, it's like an application form). My requirement is to fill such documents with information entered using a WPF desktop application. Basically the same document using for multiple occasions.

How can I do this with .Net. I tried to create the whole document when required. But it has lots of work to do for a single document. Is there a way to inject the content into the word document, may be as a template.

Thanks in advance.
Posted
Comments
Mario Z 20-Jul-15 5:15am    
There are couple of ways how you can do that. For example you can define bookmarks in the document which you would fill with the desired content or you could use merge fields and replace them with a required data (so called mail merge process) or you could define some custom placeholders in your document and use find & replace.
The easiest approah will probably depend on what you are considering to use for processing your documents in .NET, is it Word Interop, OpenXML SDK, something else?
CodingLover 20-Jul-15 7:40am    
Actually I'm going to user Word Interop for this case.

1 solution

Here is a helper class I put in my project (its in VB.NET, you can easily convert it to C#). This is how it works:
1. create word template (.dot file)
2. add bookmarks to places where you need to set the data
3. format the table (currently supports only one), set headers etc AND HAVE ONE EMPTY ROW of the table. The table has to be bookmarked too.
4. Create new WordReport object, set template name, call Add ("BookmarkName", bookmarkData) as many times as you need it
4a. if you're filling the table then give the list of column names in stringArray
5. Call Print and you're done :) - it will open word document with filled data.

VB
Imports Microsoft.Office.Interop
Imports PADOVA.Common.Utilities

Public Class WordReport
#Region "Constructor"
    Public Sub New()
        If Bookmarks Is Nothing Then
            Bookmarks = New List(Of String)
        End If

        If BookmarkData Is Nothing Then
            BookmarkData = New Hashtable
        End If
    End Sub
#End Region

#Region "Variables"
    Private logger As NLog.Logger = NLog.LogManager.GetCurrentClassLogger
#End Region

#Region "Properties"
    Public Property TemplateName As String
    Public Property Bookmarks As List(Of String)
    Public Property BookmarkColumns As Hashtable
    Public Property BookmarkData As Hashtable
    Public Property GroupByIndex As Integer

    Public Property ShowTableCount As Boolean = True
#End Region

#Region "Helpers"
    Public Sub Add(bookmarkName As String, bookmarkData As Object)
        If bookmarkName.Trim = String.Empty Then
            Throw New ArgumentException("Naziv bookmarka ne može biti prazan!")
            Return
        End If

        Me.Bookmarks.Add(bookmarkName)
        Me.BookmarkData.Add(bookmarkName, bookmarkData)
    End Sub

    Public Sub Add(bookmarkName As String, bookmarkData As Object, bookmarkColumns As List(Of String))
        Me.Add(bookmarkName, bookmarkData)

        If bookmarkColumns IsNot Nothing Then
            If Me.BookmarkColumns Is Nothing Then
                Me.BookmarkColumns = New Hashtable
            End If

            Me.BookmarkColumns.Add(bookmarkName, bookmarkColumns)
        End If
    End Sub

    Public Sub Add(bookmarkName As String, bookmarkData As Object, bookmarkColumns As String())
        Dim list As List(Of String) = Nothing
        If bookmarkColumns IsNot Nothing Then
            If list Is Nothing Then
                list = New List(Of String)
            End If
            For Each s As String In bookmarkColumns
                list.Add(s)
            Next
        End If

        Me.Add(bookmarkName, bookmarkData, list)
    End Sub

    Public Sub Print()
        If TemplateName.Trim = String.Empty Then
            Throw New ArgumentException("Template name not set!")
            Return
        End If

        If Not IO.File.Exists(TemplateName) Then
            Throw New ArgumentException("Template file not found by given name!")
            Return
        End If


        Dim appWord As Word.Application = Nothing
        Dim appWordDocument As Word.Document = Nothing
        Try
            appWord = CType(CreateObject("Word.Application"), Word.Application)
            Application.DoEvents()
            appWordDocument = appWord.Documents.Add(CObj(TemplateName))
            Application.DoEvents()

            Dim data As Object = Nothing
            Dim bookmark As Word.Bookmark = Nothing
            Dim columns As List(Of String) = Nothing

            Dim reportDataTable As DataTable = Nothing

            For Each bm As String In Bookmarks
                bookmark = appWordDocument.Bookmarks(bm)
                If bookmark Is Nothing Then Continue For

                data = BookmarkData(bm)

                If TypeOf data Is DataTable Then
                    columns = BookmarkColumns(bm)
                    If bookmark.Range.Tables.Count = 0 Then Continue For

                    Dim table As Word.Table = bookmark.Range.Tables(1)

                    reportDataTable = DirectCast(data, DataTable)
                    Dim row As DataRow = Nothing
                    Dim lastRowValue As String = String.Empty
                    For index As Integer = 0 To reportDataTable.Rows.Count - 1
                        row = reportDataTable.Rows(index)

                        Dim newRow As Word.Row = table.Rows.Add(table.Rows.Last)

                        For i As Integer = 1 To columns.Count
                            ' ukoliko treba grupirati po određenoj koloni, a nije zadnji red makni gornji border
                            If i = GroupByIndex Then
                                If NullToString(row(columns(i - 1))).Trim = lastRowValue Then
                                    newRow.Cells(i).Range.Text = String.Empty

                                    'If index <> reportDataTable.Rows.Count - 1 Then
                                    Dim borders As Word.Borders = newRow.Cells(i).Range.Borders
                                    Dim border As Word.Border = borders(Word.WdBorderType.wdBorderTop)
                                    border.LineStyle = Word.WdLineStyle.wdLineStyleNone
                                    'End If
                                Else
                                    newRow.Cells(i).Range.Text = NullToString(row(columns(i - 1))).Trim
                                End If

                                lastRowValue = NullToString(row(columns(i - 1))).Trim
                            Else
                                newRow.Cells(i).Range.Text = NullToString(row(columns(i - 1))).Trim
                            End If
            Next
                    Next

                    If ShowTableCount Then
                        Dim totals As Word.Row = table.Rows.Last
                        If totals.Cells.Count > 1 Then
                            With totals.Cells(totals.Cells.Count - 1).Range
                                .Text = "TOTAL"
                                .Bold = 1
                            End With

                            totals.Cells(totals.Cells.Count).Range.Text = reportDataTable.Rows.Count.ToString
                        End If
                    Else
                        table.Rows.Last.Delete()
                    End If
                Else
                    ' nemoj prepisivati defaultni tekst s template-a ako nema ništa za upisati
                    If NullToString(data).Trim <> String.Empty Then

                        bookmark.Range.Text = NullToString(data).Trim
                    End If
                End If
            Next

            appWord.Visible = True
            Application.DoEvents()

            appWord.ActiveDocument.Protect(Word.WdProtectionType.wdAllowOnlyReading, False, String.Empty, False, False)
            Application.DoEvents()
        Catch ex As Exception
            MsgBox("Error in filling the report data.", MsgBoxStyle.Exclamation)
            logger.Error("{0}: {1}: {2}", Now.ToString, "WordReport:Print", ex)
        Finally
            If appWordDocument IsNot Nothing Then
                System.Runtime.InteropServices.Marshal.ReleaseComObject(appWordDocument)
            End If

            If appWord IsNot Nothing Then
                System.Runtime.InteropServices.Marshal.ReleaseComObject(appWord)
            End If
        End Try
    End Sub

#End Region
End Class



This is how you're filling the report:
VB
Private Sub IspisNepravilnosti(ispisNepravilnosti As DataTable)
        Try
            If _nepravilnostZapisnikId = 0 Then Return

            Dim zm As New ZapisniciManager(GlobalContext)
            Dim zapisnik As DataSet = zm.GetZapisnik(_nepravilnostZapisnikId)

            If zapisnik Is Nothing OrElse zapisnik.Tables.Count = 0 OrElse zapisnik.Tables(0).Rows.Count = 0 Then
                MsgBox("Ispis nepravilnosti nije uspio!", MsgBoxStyle.Exclamation)
                Return
            End If

            Dim wr As New WordReport
            With wr
                Dim templatePath As String = IO.Path.Combine(ApplicationExecutablePath, "wordtemplates")
                Dim templateFile As String = IO.Path.Combine(templatePath, "IspisNepravilnosti.dot")
                .TemplateName = templateFile
                .ShowTableCount = False
                .GroupByIndex = 1

                .Add("BrojKutije", mtxtNinIdKutije.Text.Trim.ToUpperInvariant)
                .Add("BrojZapisnika", zapisnik.Tables(0).Rows(0).Item("prikaz_broja_zapisnika"))


                .Add("ListaNepravilnosti", ispisNepravilnosti, {"NAZIV_NEDOSTATKA", "ZADUZNICE", "KLIJENT", "BROJ_OVJERE"})
                '.Add("Napomena", "??")

                .Add("OvlasteniRadnik1", GlobalContext.ImePrezime.ToUpper)
                '.Add("OvlasteniRadnik2", "") ' ne koristi se, odn. radnik treba ručno upisati
                .Add("DatumNepravilnosti", Today.ToString("dd.MM.yyyy"))


                .Print()
            End With
        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Exclamation)
        End Try
    End Sub
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900