有个WPF做的客户端在完成任务后需要出具一份受控报告,详情如下。
目的:根据word模板结合具体数据生成word报告
技术路径:word模板包含书签,生成报告时具体数据替换对应的书签,书签类型有字符串和表格两种。
需求:
○ 能够将word书签替换为字符串、表格;
○添加页脚:能够获取当前页面页数,以及总页数
现有c# word库调研:
综上,优先推荐DocX、Microsoft.Office.Interop.Word,两者主要区别在于是否依赖Office,在使用便利性上DocX优于Microsoft.Office.Interop.Word,DocX操作逻辑上更为简单,但功能上应该还是Microsoft.Office.Interop.Word更全,毕竟Office是成熟的产品,有微软爸爸背书。
最初使用的是Microsoft.Office.Interop.Word,但后来有个客户电脑出word会报如下错误,后来试了几种方法没解决,最后便使用DocX库避免依赖Office解决这个问题。
最后,由于没有深入研究DocX页脚功能,便提前利用Microsoft.Office.Interop.Word制作包含页脚的word模板,然后使用DocX将具体内容(字符串 && 表格)填入并生成word报告。
Microsoft.Office.Interop.Word代码
public void report(ref ReportData reportData, string templatePath, string reportPath)
{
if (!File.Exists(templatePath)) return;
try
{
Word.Application app = new Word.Application();
app.Visible = false;
Word.Document doc = app.Documents.Open(templatePath);//打开word文件
object missing = System.Reflection.Missing.Value;
string allBookMarkString = "";
foreach (Word.Bookmark bookmark in doc.Bookmarks)
{
allBookMarkString += bookmark.Name;
if (bookmark.Name == "RawData")
{
//Word.Bookmark bk = doc.Bookmarks["RawData"];
Word.Range range = bookmark.Range;
Word.Table table = doc.Tables.Add(range, 6, 7, ref missing, ref missing);
table.Borders.Enable = 1;
inserTableData(ref table, ref reportData);
}
}
Dictionary<string, string> dicData = reportData.ProjectData.getDictionary();
foreach (var item in dicData)
{
if (item.Value == null) continue;
if (allBookMarkString.Contains(item.Key))
doc.Bookmarks[item.Key].Range.Text = item.Value;
}
setFooter(ref app);
//保存
object filename = reportPath;
doc.SaveAs(ref filename, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing);
doc.Close(ref missing, ref missing, ref missing);
if (app != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
app = null;
}
GC.Collect();
System.Diagnostics.Process[] excelprocess = System.Diagnostics.Process.GetProcessesByName("WINWORD");
foreach (System.Diagnostics.Process pr in excelprocess)
{
pr.Kill();//停止关联进程
}
}
catch (Exception ex)
{
MessageBox.Show("报告生成失败!\n原因: " + ex.Message);
}
try
{
if (File.Exists(reportPath))
CommonFunction.openFile(reportPath);
}
catch (Exception ex)
{
MessageBox.Show("报告打开失败!\n原因: " + ex.Message);
}
}
//设置页脚
/* 第 页 共 页
* PAGE_OF_
*/
void setFooter(ref Word.Application app)
{
object missing = System.Reflection.Missing.Value;
app.ActiveWindow.ActivePane.View.SeekView = Microsoft.Office.Interop.Word.WdSeekView.wdSeekCurrentPageFooter;
app.ActiveWindow.ActivePane.Selection.Paragraphs.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphCenter;
app.ActiveWindow.Selection.TypeText("第");
Object CurrentPage = Word.WdFieldType.wdFieldPage;
app.ActiveWindow.Selection.Fields.Add(app.ActiveWindow.Selection.Range, ref CurrentPage, ref missing, ref missing);
app.ActiveWindow.Selection.TypeText("页 共");
Object TotalPages = Word.WdFieldType.wdFieldNumPages;
app.ActiveWindow.Selection.Fields.Add(app.ActiveWindow.Selection.Range, ref TotalPages, ref missing, ref missing);
app.ActiveWindow.Selection.TypeText("页\n");
/* Insert current page number "Page X of N" on a word document */
/*======================================================================*/
// Open up the footer in the word document
app.ActiveWindow.ActivePane.View.SeekView = Microsoft.Office.Interop.Word.WdSeekView.wdSeekCurrentPageFooter;
// Set current Paragraph Alignment to Center
app.ActiveWindow.ActivePane.Selection.Paragraphs.Alignment = Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphCenter;
// Type in 'Page '
app.ActiveWindow.Selection.TypeText("PAGE");
// Add in current page field
CurrentPage = Word.WdFieldType.wdFieldPage;
app.ActiveWindow.Selection.Fields.Add(app.ActiveWindow.Selection.Range, ref CurrentPage, ref missing, ref missing);
// Type in ' of '
app.ActiveWindow.Selection.TypeText("OF");
// Add in total page field
TotalPages = Word.WdFieldType.wdFieldNumPages;
app.ActiveWindow.Selection.Fields.Add(app.ActiveWindow.Selection.Range, ref TotalPages, ref missing, ref missing);
/*======================================================================*/
}
void inserTableData(ref Word.Table table,ref ReportData reportData)
{
try
{
if (table == null) return;
List<string> allNames = reportData.BodySectionData.getAllPointNames();
List<Point_3D> actualPoints = reportData.BodySectionData.getValue(false);
int nowSectionIndex = reportData.Index;
List<Point_3D> actualPointsNoBias = reportData.ActualPointsNoBias.GetRange(nowSectionIndex * 4, 4);
if (allNames.Count != 4 || actualPoints.Count != 4 || actualPointsNoBias.Count != 4)
return;
if (allNames[0] == null || actualPoints[0] == null || actualPointsNoBias[0] == null)
return;
try
{
//设置表格标题
table.Cell(1, 1).Range.Text = "水平测量点";
table.Cell(1, 5).Range.Text = "实测值(去偏置)";
table.Cell(1, 2).Range.Text = "实测值(带偏置)";
}
catch (Exception e)
{
MessageBox.Show("表格标题设置出现错误!");
}
//合并单元格
table.Cell(1, 1).Merge(table.Cell(2, 1));
table.Cell(1, 5).Merge(table.Cell(1, 7));
table.Cell(1, 2).Merge(table.Cell(1, 4));
for (int i = 0; i < 2; i++)
{
table.Cell(2, i * 3 + 4).Range.Text = "Z(mm)";
table.Cell(2, i * 3 + 2).Range.Text = "X(mm)";
table.Cell(2, i * 3 + 3).Range.Text = "Y(mm)";
}
table.Cell(3, 1).Range.Text = allNames[0];
table.Cell(4, 1).Range.Text = allNames[1];
table.Cell(5, 1).Range.Text = allNames[2];
table.Cell(6, 1).Range.Text = allNames[3];
insertPoints(ref table, ref actualPoints, 3, 2);
insertPoints(ref table, ref actualPointsNoBias, 3, 5);
}
catch (Exception ex)
{
MessageBox.Show("Word 插入表格错误: " + ex.Message);
return;
}
}
void insertPoints(ref Word.Table table,ref List<Point_3D> points, int beginRow, int beginCol)
{
for(int row= beginRow, index=0; index< points.Count;row++,index++)
{
if (points[index] == null)
return;
table.Cell(row, beginCol).Range.Text = String.Format("{0:f3}", points[index].x);
table.Cell(row, beginCol + 1).Range.Text = String.Format("{0:f3}", points[index].y);
table.Cell(row, beginCol + 2).Range.Text = String.Format("{0:f3}", points[index].z);
}
}
DocX代码
class DocXHelper
{
public DocXHelper()
{
//string exePath = System.AppDomain.CurrentDomain.BaseDirectory;
//string readPath = exePath + "Word-Template.docx";
//string savePath = exePath + "copyFile.docx";
//report(readPath, savePath);
//MessageBox.Show(" 完成!");
}
public void report(ref ReportData reportData, string templatePath, string reportPath)
{
if (!File.Exists(templatePath)) return;
using (var document = DocX.Load(templatePath))
{
Dictionary<string, string> dicData = reportData.ProjectData.getDictionary();
foreach (var bookmark in document.Bookmarks)
{
if (bookmark.Name == "RawData")
{
try
{
Table table = bookmark.Paragraph.InsertTableBeforeSelf(6, 7);//插入段落后
table.Design = TableDesign.TableGrid;
table.Alignment = Alignment.center;
table.AutoFit = AutoFit.Contents;
inserTableData(table, ref reportData);
}
catch(Exception e)
{
MessageBox.Show("DocX生成报告失败!", "提示");
}
}
else
{
if(dicData.ContainsKey(bookmark.Name))
bookmark.Paragraph.Append(dicData[bookmark.Name]);
}
}
document.SaveAs(reportPath); //document.SaveAs(outFile);
try
{
if (File.Exists(reportPath))
CommonFunction.openFile(reportPath);
}
catch (Exception ex)
{
MessageBox.Show("报告打开失败!\n原因: " + ex.Message);
}
}
}
void inserTableData(Table table, ref ReportData reportData)
{
try
{
if (table == null) return;
List<string> allNames = reportData.BodySectionData.getAllPointNames();
List<Point_3D> actualPoints = reportData.BodySectionData.getValue(false);
int nowSectionIndex = reportData.Index;
List<Point_3D> actualPointsNoBias = reportData.ActualPointsNoBias.GetRange(nowSectionIndex * 4, 4);
if (allNames.Count != 4 || actualPoints.Count != 4 || actualPointsNoBias.Count != 4)
return;
if (allNames[0] == null || actualPoints[0] == null || actualPointsNoBias[0] == null)
return;
try
{
//设置表格标题
setCellText(table, 1, 1, "水平测量点");
setCellText(table, 1, 2, "实测值(带偏置)");
setCellText(table, 1, 5, "实测值(去偏置)");
mergeCol(table, 1, 1, 2);
mergeRow(table, 1, 5, 7);
mergeRow(table, 1, 2, 4);
}
catch (Exception e)
{
MessageBox.Show("表格标题设置出现错误!");
}
for (int i = 0; i < 2; i++)
{
setCellText(table, 2, i * 3 + 2, "X(mm)");
setCellText(table, 2, i * 3 + 3, "Y(mm)");
setCellText(table, 2, i * 3 + 4, "Z(mm)");
}
for (int i=0;i< allNames.Count;i++)
setCellText(table, 3 + i, 1, allNames[i]);
insertPoints(ref table, ref actualPoints, 3, 2);
insertPoints(ref table, ref actualPointsNoBias, 3, 5);
}
catch (Exception ex)
{
MessageBox.Show("Word 插入表格错误: " + ex.Message);
return;
}
}
void insertPoints(ref Table table, ref List<Point_3D> points, int beginRow, int beginCol)
{
for (int row = beginRow, index = 0; index < points.Count; row++, index++)
{
if (points[index] == null)
return;
setCellText(table, row, beginCol, String.Format("{0:f3}", points[index].x));
setCellText(table, row, beginCol + 1, String.Format("{0:f3}", points[index].y));
setCellText(table, row, beginCol + 2, String.Format("{0:f3}", points[index].z));
}
}
//row and col are counted from 1
void mergeRow(Table table, int mergeRow,int beginCol,int endCol)
{
if (mergeRow > table.RowCount || beginCol > table.ColumnCount || endCol > table.ColumnCount) return;
table.Rows[mergeRow - 1].MergeCells(beginCol - 1, endCol - 1);
}
//row and col are counted from 1
void mergeCol(Table table, int mergeCol, int beginRow, int endRow)
{
if (mergeCol > table.ColumnCount || beginRow > table.RowCount || endRow > table.RowCount) return;
table.MergeCellsInColumn(mergeCol - 1, beginRow - 1, endRow - 1);
}
//row and col are counted from 1
void setCellText(Table table,int row,int col,string data)
{
table.Rows[row-1].Cells[col-1].Paragraphs[0].Append(data).Alignment = Alignment.center;
}
}//DocXHelper
以上的DocX、Microsoft.Office.Interop.Word仅供参考,直接复制肯定跑不通文章来源:https://www.toymoban.com/news/detail-479092.html
参考
NPOI.XWPF允许用户操作.docx格式
Aspose.Words for .NET(无需依赖第三方应用,例如Microsoft Word, 或Office Automation,但是收费,慎用!)
Spire.Doc for .NET(收费)
c# Library for manipulating Word documents文章来源地址https://www.toymoban.com/news/detail-479092.html
到了这里,关于c#生成word报告的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!