分享使用Word物件來做合併列印的函式
前言
最常有些報表可需要用到Word的合併列印,原本想請公司買套Aspose.Word,這樣就不用在Server上裝Office,可是太貴了!只好還是透過Word Automation物件來處理。因為AP蠻常從資料庫讀出資料,然後與範本檔合併列印,所以寫個公用的Method來使用,也分享給大家。
研究
先大約了解一下Word做合併列印的步驟:
1.要先有要合併的檔案
1.1.先建立功能變數
1.2.存成範本檔
2.要有資料檔(動態產生)
3.指定範本檔的資料來源檔
4.將合併好的檔案存檔
實作
1.先建立範本檔(Example.doc)
因為是測試,所以建兩個功能變數(EMP_ID, CNAME)
2.在程式中建立測試的資料(GetMergeData)
''' <summary> ''' 取得要合併的資料 ''' </summary> ''' <returns></returns> ''' <remarks></remarks> Private Function GetMergeData() As DataTable Dim dtResult As New DataTable("Employee") With dtResult.Columns .Add("EMP_ID") .Add("CNAME") End With dtResult.Rows.Add(New Object() {"EMP_ID1", "CNAME:亂馬客"}) dtResult.Rows.Add(New Object() {"EMP_ID2", "CNAME:亂馬客2"}) Return dtResult End Function
3.在程式中依資料建立出要合併的資料檔,然後再呼叫Word執行合併列印(MergeWordFile)
''' <summary> ''' 合併列印 ''' </summary> ''' <param name="vstrExampleFileName"></param> ''' <param name="vdtData"></param> ''' <param name="vstrDesFileName"></param> ''' <returns></returns> ''' <remarks></remarks> Public Function MergeWordFile(ByVal vstrExampleFileName As String, ByVal vdtData As DataTable, ByVal vstrDesFileName As String) As Boolean Dim blnResult As Boolean = False Dim wrdApp As Object 'Microsoft.Office.Interop.Word.Application Dim wrdDoc As Object 'Microsoft.Office.Interop.Word.Document Try wrdApp = CreateObject("Word.Application") 'New Microsoft.Office.Interop.Word.Application wrdApp.Visible = False wrdApp.DisplayAlerts = 0 'Microsoft.Office.Interop.Word.WdAlertLevel.wdAlertsNone wrdDoc = wrdApp.Documents.Open(FileName:=vstrExampleFileName, ConfirmConversions:=False, ReadOnly:=False) wrdDoc.MailMerge.MainDocumentType = 0 ' Microsoft.Office.Interop.Word.WdMailMergeMainDocType.wdFormLetters '準備要合併的Word檔 Dim wrdDSDoc As Object 'Microsoft.Office.Interop.Word.Document wrdDSDoc = wrdApp.Documents.Add wrdDSDoc.Select() wrdApp.Selection.WholeStory() '建立Title Dim strbTitle As New Text.StringBuilder For Each dcData As DataColumn In vdtData.Columns If strbTitle.Length > 0 Then strbTitle.Append(",") End If strbTitle.Append(dcData.ColumnName) Next wrdApp.Selection.TypeText(strbTitle.ToString) '建立資料列 For Each drData As DataRow In vdtData.Rows Dim strbData As New Text.StringBuilder For Each dcData As DataColumn In vdtData.Columns If strbData.Length > 0 Then strbData.Append(",") End If strbData.Append("""" & GetColumnValue(drData, dcData.ColumnName) & """") Next wrdApp.Selection.TypeParagraph() wrdApp.Selection.TypeText(strbData.ToString) Next Dim strNewDSFile As String = Path.Combine(Path.GetDirectoryName(vstrExampleFileName), Guid.NewGuid.ToString & ".doc") wrdDSDoc.SaveAs(strNewDSFile) wrdDSDoc.Close(False) With wrdDoc.MailMerge .OpenDataSource(strNewDSFile) .Destination = 0 'Microsoft.Office.Interop.Word.WdMailMergeDestination.wdSendToNewDocument .Execute(False) End With wrdDoc.Saved = True wrdApp.Windows(1).Activate() wrdDoc.Close(False) wrdApp.ActiveDocument.SaveAs(vstrDesFileName) wrdApp.ActiveDocument.Close() wrdApp.Quit(False) blnResult = True Catch ex As Exception blnResult = False 'Throw MsgBox(ex.ToString) Finally If IsNothing(wrdDoc) = False Then wrdDoc = Nothing End If If IsNothing(wrdApp) = False Then wrdApp.Quit() System.Runtime.InteropServices.Marshal.ReleaseComObject(wrdApp) wrdApp = Nothing End If End Try Return blnResult End Function
4.因為資料有可能會有DBNull,所以直接用GetColumnValue來處理。
''' <summary> ''' 取得欄位值,如果為Null就回傳空字串 ''' </summary> ''' <param name="rdrValue"></param> ''' <param name="vColumnName"></param> ''' <returns></returns> ''' <remarks></remarks> Public Shared Function GetColumnValue(ByRef rdrValue As DataRow, ByVal vColumnName As String) As String Return GetColumnValue(rdrValue, vColumnName, "") End Function ''' <summary> ''' 取得欄位值,如果為Null就回傳預設的參數值 ''' </summary> ''' <param name="rdrValue"></param> ''' <param name="vColumnName"></param> ''' <param name="vstrNullDefault"></param> ''' <returns></returns> ''' <remarks></remarks> Public Shared Function GetColumnValue(ByRef rdrValue As DataRow, ByVal vColumnName As String, ByVal vstrNullDefault As String) As String If rdrValue.IsNull(vColumnName) Then Return vstrNullDefault Else Return rdrValue(vColumnName).ToString.Trim End If End Function
5.範例程式說明
本範例會取得範例檔並依資料動態產生資料檔(GUID.doc),然後將合併後的檔案存到目的檔,如下圖所示。
Private Sub btnMerge_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnMerge.Click Dim strAppDirPath As String = Path.GetDirectoryName(Application.ExecutablePath) '檔案為執行目錄所在的檔案 Dim strExampleFile As String = Path.Combine(strAppDirPath, txtExampleFile.Text) Dim strDestFile As String = Path.Combine(strAppDirPath, txtDestFile.Text) If MergeWordFile(strExampleFile, GetMergeData, strDestFile) = False Then MsgBox("合併失敗!") Else MsgBox("合併成功!") End If End Sub
結論
如果有$的話,真的建議買Aspose的產品。另外,有可能在做Word的合併列印時,會發生”Word 無法啟動轉換程式 mswrd632.wpc”的錯誤!這可能是因為上了MS的Update所造成的! 可以http://support.microsoft.com/kb/973904到修正這個問題哦!
各位如果有更好的方式,也請告訴我! 謝謝!
附上範例程式:WordMailMerge.rar
Hi,
亂馬客Blog已移到了 「亂馬客 : Re:從零開始的軟體開發生活」
請大家繼續支持 ^_^