编程应用中经常要报表。
本文摘自vs2015、netframework4.61、vb.net源代码,代码本身均不依赖于word环境。
方法一:使用DocX
我需要生成这样的表,下图是mb_MC.docx:
''''安装并引用包,.Net FrameWork 4.0 ,Docx.dll
''install-package docx -version 1.3.0
Imports Xceed.Words.NET
Sub do_Docx()
Dim dx As DocX = DocX.Load("mb_MC.docx")
Dim t = dx.Tables(0)
Dim r0 = t.Rows(1)'备份第二行,含格式
Dim nr =8, nc =6
Dim ir, ic As Integer
For ir = 0 To nr
Dim r1 As Row = t.InsertRow(r0, ir + 2) '相当于复制第二行,后面均对新行处理
For ic = 0 To nc - 1 '填文本
Dim tx ="字段值" '数据来源DataTable的行,...
Dim p0 = r1.Cells(ic).Paragraphs(0).Append(tx) '如果格内有其它内容,可以改为替换
'p0的格式设置...
Next
Dim p = r1.Cells(nc).Paragraphs(0) '最后列添加图片
Dim f1 = "you关联图片.jpg"
If File.Exists(f1) Then
Dim img As Image = dx.AddImage(f1)
Dim pic = p.AppendPicture(img.CreatePicture(44, 33)) '填图片,设置高、宽
Else
p.Append("没照片")
End If
Next
t.RemoveRow(1)
dx.SaveAs("f.docx")
End Sub
感谢作者:https://github.com/xceedsoftware/docx
方法二:使用TemplateEngine.Docx
模板的创建mb_MC_T.docx(用到了内容控件和图片控件,需要重复的行由内容控件T1包裹):
'Install-Package TemplateEngine.Docx -Version 1.1.4 '.net46+
Imports TemplateEngine.Docx
Sub do_DocxT(dt as DataTable,fDx as Sring)
File.Copy("mb_MC_T.docx", fDx, True) '要Try
Dim TC = New TableContent("T1") '创建表行重复
For Each dr As DataRow In dt.Rows
Dim ar1 = New List(Of IContentItem)() '文档一行,含FieldContent和ImageContent
''内容字段
For Each c as DataColumn in dt.Columns
dim k = c.ColumnName
dim v = dr(k).ToString()
ar1.Add(new FieldContent(k, v))
Next
''添加照片,在模板中为 图片控件
Dim f1 = "you关联图片.jpg"
Dim bb As Byte()=If(File.Exists(f1),File.ReadAllBytes(f1),New Byte() {}) '读wu.jpg
ar1.Add(New ImageContent("pic", bb))
''一行
TC.AddRow(ar1.ToArray())
Next
Dim fillData = New Content(TC,
New FieldContent("other", "其它内容值"))
Using TP As TemplateProcessor = New TemplateProcessor(fDx)
TP.SetRemoveContentControls(True).SetNoticeAboutErrors(False)'debug时:True
TP.FillContent(fillData)
'在此,还有啥要处理:TP.Document.Descendants ... ...
TP.SaveChanges()
End Using
Process.Start(fDx) 'try
End Sub
有Content、TableContent、FieldContent、ImageContent、RepeatContent、ListContent等等
感谢作者:https://github.com/UNIT6-open/TemplateEngine.Docx
方法三:直接生成rtf吧
用编辑软件做模板,另存为rtf,经写字板(wordpad.exe)打开、保存,精简一下,内容行就是这样子的:
xxxcell xxxcell xxxcell xxxcell xxxcell xxxcell <图片串>cellrow
Private Sub do_Rtf(rr As DataRow(), f0 As String)
Dim sw As StreamWriter
Try
sw = New StreamWriter(f0, False, System.Text.Encoding.Default) '不追加
Catch e As Exception
MsgBox(e.Message, MsgBoxStyle.Critical)
Exit Sub
End Try
Dim rtfH = "{rtf1ansi {fonttbl{f15fnil 宋体}{f16fnil 黑体}}
{colortbl;red0green0blue255;red0green255blue0;red255green255blue0;red255green0blue0;red0green0blue0;}
paperw16840paperh11907margl880margr880margt880margb567gutter0 lndscpsxnviewkind1viewscale100headery600footery567
{header brdrbbrdrsbrdrw5 fs18cf5qj par}
{footer fs18cf5qr {field{*fldinst {PAGE}}} / {field{*fldinst {NUMPAGES}}} 页 par }".Replace("", f0)
sw.WriteLine(rtfH)
'列头、列宽,对应
Dim cc = {"学号", "姓名", "性别", "", "", "", "照片"}
Dim cw As Single() = {2.7, 1.7, 1, 2.0, 2.0, 2.0, 1.5} 'cm
sw.WriteLine("fs18trowdtrqctrleft-108trrh400")
'表格定义
Dim ww As Integer = 0
For i As Integer = 0 To cw.Length - 1
ww += cw(i) * 567
sw.WriteLine("clvertalcclbrdrtbrdrsclbrdrlbrdrsclbrdrbbrdrsclbrdrrbrdrscltxlrtb cellx" & ww)
Next
sw.Write("pard intbl{")'开始 intbl
'表头行
sw.Write("qc fs21 {bqc ")
sw.Write(String.Join("cell ", cc))
sw.WriteLine("cellrow}")
'表格内容行,循环
sw.Write(trrh567") '行高1CM
For Each r As DataRow In rr
'文本列
''sw.Write("qc ")
For ic = 0 To cc.Length - 2
sw.Write(r(cc(ic)).ToString() & "cell ")
Next
'照片
Dim ff = "you关联照片.jpg"
Dim zp = If(File.Exists(ff), rtf_PicStr(ff, 495), "无照片")
sw.WriteLine($"qc {zp}cellrow")
Next
sw.WriteLine("}pard") ''end intbl
sw.WriteLine("}") ''end rtf
sw.Flush()
sw.Close()
End Sub
链接图片文件名就简单了。内嵌的rtf图片串难搞?
Private Function rtf_picStr(fjpg As String, w缇 As Integer) As String
'1 twips缇的长度等于1/1440英寸;1/567厘米;1/20磅;1英寸=2.54厘米
If not File.Exists(fjpg) Then Return ""
Dim s = ""
Dim m = New System.IO.MemoryStream()
Try
Dim bp = New System.Drawing.Bitmap(fjpg)
bp.Save(m, System.Drawing.Imaging.ImageFormat.Jpeg)
Dim h缇 As Integer = w缇 * bp.Height / bp.Width '保持长宽比
Dim s1 = $"pictjpegblippicwgoal{w缇}pichgoal{h缇}hex "
Dim s2 As String =BitConverter.ToString(m.GetBuffer(), 0).Replace("-", String.Empty)
bp.Dispose()
s = "{*shppict{" & s1 & s2 & "}}"
Catch
s = "无"
Finally
m.Close()
m.Dispose()
End Try
Return s
End Function
如果你有空闲时间优化rtf模板,这是运行最快的方法了。
更多的方法:
直接生成xml,类似于rtf;
还可以用openxml SDK生成代码…
值得参考java下poi-tl:http://deepoove.com/poi-tl/
End,vs2015,NetFramework4.61测试通过。



