C# 处理Word自动生成报告 四、程序处理
现在说一下程序处理部分,有点长
本来是想做针对doc和docx的模板两个版本, 后来想到可以在生成的时候saveas里设置格式,
所以此版只支持对docx的模板处理,
想要doc的情况可以选择生成格式为doc的.
上代码:
public class WordHelper
{
private Word.Application wordApp = null;
private Word.Document wordDoc = null;
private DataSet dataSource = null;
private object line = Word.WdUnits.wdLine;
private string errorMsg = "";
/// <summary>
/// 根据模板文件,创建数据报告
/// </summary>
/// <param name="templateFile">模板文件名(含路径)</param>
/// <param name="newFilePath">新文件路径)</param>
/// <param name="dataSource">数据源,包含多个datatable</param>
/// <param name="saveFormat">新文件格式:</param>
)
{
this.dataSource = dataSource;
errorMsg = this.errorMsg;
bool rtn = OpenTemplate(templateFile)
&& SetContent(].Rows[]))
&& UpdateTablesOfContents()
&& SaveFile(newFilePath, ref newFileName, saveFormat);
CloseAndClear();
return rtn;
}
private bool OpenTemplate(string templateFile)
{
if (!File.Exists(templateFile))
{
return false;
}
wordApp = new Word.ApplicationClass();
wordApp.Visible = false;//使文档可见,调试用
wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
object file = templateFile;
wordDoc = wordApp.Documents.Open(ref file, ReadOnly: true);
return true;
}
private bool SetContent(WordElement element)
{
string currBookMarkName = string.Empty;
).ToString() + "_";
foreach (Word.Bookmark item in element.Range.Bookmarks)
{
currBookMarkName = item.Name;
if (currBookMarkName.StartsWith(startWith) && (!currBookMarkName.Equals(element.ElementName)))
{
SetLoop(new WordElement(item.Range, currBookMarkName, element.DataRow, element.GroupBy));
}
}
SetLabel(element);
SetTable(element);
SetChart(element);
return true;
}
private bool SetLoop(WordElement element)
{
DataRow[] dataRows = dataSource.Tables[element.TableIndex].Select(element.GroupByString);
int count = dataRows.Count();
element.Range.Select();
//第0行作为模板 先从1开始 循环后处理0行;
; i < count; i++)
{
element.Range.Copy(); //模板loop复制
wordApp.Selection.InsertParagraphAfter();//换行 不会清除选中的内容,TypeParagraph 等同于回车,若当前有选中内容会被清除. TypeParagraph 会跳到下一行,InsertParagraphAfter不会, 所以movedown一下.
wordApp.Selection.MoveDown(ref line, Missing.Value, Missing.Value);
wordApp.Selection.Paste(); //换行后粘贴复制内容
int offset = wordApp.Selection.Range.End - element.Range.End; //计算偏移量
//复制书签,书签名 = 模板书签名 + 复制次数
foreach (Word.Bookmark subBook in element.Range.Bookmarks)
{
if (subBook.Name.Equals(element.ElementName))
{
continue;
}
wordApp.Selection.Bookmarks.Add(subBook.Name + "_" + i.ToString(), wordDoc.Range(subBook.Start + offset, subBook.End + offset));
}
SetContent(new WordElement(wordDoc.Range(wordApp.Selection.Range.End - (element.Range.End - element.Range.Start), wordApp.Selection.Range.End), element.ElementName + "_" + i.ToString(), dataRows[i], element.GroupBy));
}
element.Range.Delete();
return true;
}
private bool SetLabel(WordElement element)
{
)
{
string startWith = "label_" + element.Level.ToString() + "_";
string bookMarkName = string.Empty;
foreach (Word.Bookmark item in element.Range.Bookmarks)
{
bookMarkName = item.Name;
if (bookMarkName.StartsWith(startWith))
{
bookMarkName = WordElement.GetName(bookMarkName);
item.Range.Text = element.DataRow[bookMarkName].ToString();
}
}
}
return true;
}
private bool SetTable(WordElement element)
{
)
{
string startWith = "table_" + element.Level.ToString() + "_";
foreach (Word.Table table in element.Range.Tables)
{
if (!string.IsNullOrEmpty(table.Title) && table.Title.StartsWith(startWith))
{
WordElement tableElement = new WordElement(null, table.Title, element.DataRow);
TableConfig config = new TableConfig(table.Descr);
object dataRowTemplate = table.Rows[config.DataRow];
Word.Row SummaryRow = null;
DataRow SummaryDataRow = null;
DataTable dt = dataSource.Tables[tableElement.TableIndex];
DataRow[] dataRows = dataSource.Tables[tableElement.TableIndex].Select(tableElement.GroupByString); ;
)
{
SummaryRow = table.Rows[config.SummaryRow];
SummaryDataRow = dt.Select(string.IsNullOrEmpty(tableElement.GroupByString) ? config.SummaryFilter : tableElement.GroupByString + " and " + config.SummaryFilter).FirstOrDefault();
}
foreach (DataRow row in dataRows)
{
if (row == SummaryDataRow)
{
continue;
}
Word.Row newRow = table.Rows.Add(ref dataRowTemplate);
; j < table.Columns.Count; j++)
{
newRow.Cells[j + ].Range.Text = row[j].ToString(); ;
}
}
((Word.Row)dataRowTemplate).Delete();
&& SummaryDataRow != null)
{
; j < SummaryRow.Cells.Count; j++)
{
].Range.Text.Trim().Replace("\r\a", "");
&& dt.Columns.Contains(temp.Substring(, temp.Length - )))
{
SummaryRow.Cells[j + ].Range.Text = SummaryDataRow[temp.Substring(, temp.Length - )].ToString();
}
}
}
table.Title = tableElement.Name;
}
}
}
return true;
}
private bool SetChart(WordElement element)
{
)
{
List<Word.InlineShape> chartList = element.Range.InlineShapes.Cast<Word.InlineShape>().Where(m => m.Type == Word.WdInlineShapeType.wdInlineShapeChart).ToList();
string startWith = "chart_" + element.Level.ToString() + "_";
foreach (Word.InlineShape item in chartList)
{
Word.Chart chart = item.Chart;
if (!string.IsNullOrEmpty(chart.ChartTitle.Text) && chart.ChartTitle.Text.StartsWith(startWith))
{
WordElement chartElement = new WordElement(null, chart.ChartTitle.Text, element.DataRow);
DataTable dataTable = dataSource.Tables[chartElement.TableIndex];
DataRow[] dataRows = dataTable.Select(chartElement.GroupByString);
int columnCount = dataTable.Columns.Count;
List<int> columns = new List<int>();
foreach (var dr in dataRows)
{
? : chartElement.ColumnStart - ; i < (chartElement.ColumnEnd == - ? columnCount : chartElement.ColumnEnd); i++)
{
if (columns.Contains(i) || dr[i] == null || string.IsNullOrEmpty(dr[i].ToString()))
{
}
else
{
columns.Add(i);
}
}
}
columns.Sort();
columnCount = columns.Count;
int rowsCount = dataRows.Length;
Word.ChartData chartData = chart.ChartData;
//chartData.Activate();
//此处有个比较疑惑的问题, 不执行此条,生成的报告中的图表无法再次右键编辑数据. 执行后可以, 但有两个问题就是第一会弹出Excel框, 处理完后会自动关闭. 第二部分chart的数据range设置总不对
//不知道是不是版本的问题, 谁解决了分享一下,谢谢
Excel.Workbook dataWorkbook = (Excel.Workbook)chartData.Workbook;
dataWorkbook.Application.Visible = false;
Excel.Worksheet dataSheet = (Excel.Worksheet)dataWorkbook.Worksheets[];
//设定范围
: rowsCount) + "|" + columnCount;
Console.WriteLine(a);
Excel.Range tRange = dataSheet.Range[ : rowsCount), columnCount]];
Excel.ListObject tbl1 = dataSheet.ListObjects[];
//dataSheet.ListObjects[1].Delete(); //想过重新删除再添加 这样 原有数据清掉了, 但觉得性能应该会有所下降
//Excel.ListObject tbl1 = dataSheet.ListObjects.AddEx();
tbl1.Resize(tRange);
; j < rowsCount; j++)
{
DataRow row = dataRows[j];
; k < columnCount; k++)
{
dataSheet.Cells[j + , k + ].FormulaR1C1 = row[columns[k]];
}
}
if (chartElement.ColumnNameForHead)
{
; k < columns.Count; k++)
{
dataSheet.Cells[, k + ].FormulaR1C1 = dataTable.Columns[columns[k]].ColumnName;
}
}
chart.ChartTitle.Text = chartElement.Name;
//dataSheet.Application.Quit();
}
}
}
return true;
}
private bool UpdateTablesOfContents()
{
foreach (Word.TableOfContents item in wordDoc.TablesOfContents)
{
item.Update();
}
return true;
}
)
{
if (string.IsNullOrEmpty(newFileName))
{
newFileName = DateTime.Now.ToString("yyyyMMddHHmmss");
switch (saveFormat)
{
:// Word.WdSaveFormat.wdFormatDocument
newFileName += ".doc";
break;
:// Word.WdSaveFormat.wdFormatDocumentDefault
newFileName += ".docx";
break;
:// Word.WdSaveFormat.wdFormatPDF
newFileName += ".pdf";
break;
default:
break;
}
}
object newfile = Path.Combine(newFilePath, newFileName);
object wdSaveFormat = saveFormat;
wordDoc.SaveAs(ref newfile, ref wdSaveFormat);
return true;
}
private void CloseAndClear()
{
if (wordApp == null)
{
return;
}
wordDoc.Close(Word.WdSaveOptions.wdDoNotSaveChanges);
wordApp.Quit(Word.WdSaveOptions.wdDoNotSaveChanges);
System.Runtime.InteropServices.Marshal.ReleaseComObject(wordDoc);
System.Runtime.InteropServices.Marshal.ReleaseComObject(wordApp);
wordDoc = null;
wordApp = null;
GC.Collect();
KillProcess("Excel","WINWORD");
}
private void KillProcess(params string[] processNames)
{
//Process myproc = new Process();
//得到所有打开的进程
try
{
foreach (string name in processNames)
{
foreach (Process thisproc in Process.GetProcessesByName(name))
{
if (!thisproc.CloseMainWindow())
{
if (thisproc != null)
thisproc.Kill();
}
}
}
}
catch (Exception)
{
//throw Exc;
// msg.Text+= "杀死" + processName + "失败!";
}
}
}
public class WordElement
{
)
{
this.Range = range;
this.ElementName = elementName;
this.GroupBy = groupBy;
this.DataRow = dataRow;
if (string.IsNullOrEmpty(elementName))
{
;
this.TableIndex = tableIndex;
this.Name = string.Empty;
this.ColumnNameForHead = false;
}
else
{
string[] element = elementName.Split('_');
]);
this.ColumnNameForHead = false;
;
;
].Equals("label"))
{
];
;
}
else
{
];
]) - ;
]))
{
].Split(new string[] { "XX" }, StringSplitOptions.RemoveEmptyEntries);
if (this.GroupBy == null)
{
this.GroupBy = new Dictionary<string, string>();
}
foreach (string item in filters)
{
if (!this.GroupBy.Keys.Contains(item))
{
this.GroupBy.Add(item, dataRow[item].ToString());
}
}
}
].Equals()
{
].Equals(");
]) ? - : ]);
]) ? - : ]);
}
}
}
}
public Word.Range Range { get; set; }
public int Level { get; set; }
public int TableIndex { get; set; }
public string ElementName { get; set; }
public DataRow DataRow { get; set; }
public Dictionary<string, string> GroupBy { get; set; }
public string Name { get; set; }
public bool ColumnNameForHead { get; set; }
public int ColumnStart { get; set; }
public int ColumnEnd { get; set; }
public string GroupByString
{
get
{
)
{
return string.Empty;
}
string rtn = string.Empty;
foreach (string key in this.GroupBy.Keys)
{
rtn += "and " + key + " = '" + GroupBy[key] + "' ";
}
);
}
}
public static string GetName(string elementName)
{
string[] element = elementName.Split('_');
].Equals("label"))
{
];
}
else
{
];
}
}
}
public class TableConfig
{
public TableConfig(string tableDescr = "")
{
;
;
if (!string.IsNullOrEmpty(tableDescr))
{
string[] element = tableDescr.Split(',');
foreach (string item in element)
{
if (!string.IsNullOrEmpty(item))
{
string[] configs = item.Split(':');
)
{
].ToLower())
{
case "data":
case "d":
]);
break;
case "summary":
case "s":
]);
break;
case "summaryfilter":
case "sf":
];
break;
default:
break;
}
}
}
}
}
}
public int DataRow { get; set; }
public int SummaryRow { get; set; }
public string SummaryFilter { get; set; }
}
后续问题: 1.部署: 目前我的开发环境里装的是office2016 的office365版 引用的是 Microsoft Word 16.0 Object Library, 对应的Microsoft.Office.Interop.Word.dll版本是15.0...
发现office2013版本也是15, 只是小版本不同, 没找到office 2016 和2013的 primary interop assembly, 莫非部署的环境里也要安装完整的office?
为了避免文件占用问题,打开模板采用了只读方式打开wordDoc = wordApp.Documents.Open(ref file, ReadOnly: true); 在office2016(office365)版测试通过, 但专业版测试失败.
ReadOnly: false的情况下, office2016 office2013均测试通过.
2. word中嵌入的Excel图表的问题, 虽然生成结果中的图表数据是正确的, 但无法右键再次编辑数据, 只可修改样式.
3. 性能问题: 处理速度较慢.
希望有知道的看到给个回复. 打算有时间研究一下OpenXML, 希望能完美解决上面的问题.
C# 处理Word自动生成报告 四、程序处理的更多相关文章
- C# 处理Word自动生成报告 三、设计模板
C# 处理Word自动生成报告 一.概述 C# 处理Word自动生成报告 二.数据源例子 C# 处理Word自动生成报告 三.设计模板 C# 处理Word自动生成报告 四.程序处理 既然是模板就少不了 ...
- C# 处理Word自动生成报告 一、概述
经常遇到这样的需求, 生成Word格式的报告, 而不是单纯的一张表格的报表. 就像体检报告一样. 数据来源部分决定采用一个存储过程返回Dataset的方式, 整张报告的数据来源于此Dataset的多 ...
- C# 处理Word自动生成报告 二、数据源例子
还是以学生.语文.数学.分数为例吧, 感觉这个和helloworld都有一拼了. 造一张表如下, 整张报表就围绕这个表转圈了, 顺便说下就是名字如有雷同纯属巧合 新建个存储过程 ALTER PROCE ...
- Word自动生成目录
博主最近在写报告的时候要在Word里面做个目录,再做个页码,然后上网搜了一些方法,非常零散,我弄了好久才弄好.在这里我把整套方法分享一下. 声明:内容完全独创! 工具:Word 2016. 效果:如下 ...
- jmeter自动生成报告
从JMeter 3.0开始已支持自动生成动态报告,我们可以更容易根据生成的报告来完成我们的性能测试报告. 如何生成html测试报告 如果未生成结果文件(.jtl),可运行如下命令生成报告: jmete ...
- 利用html实现类似于word自动生成的目录的效果
在word中的自动生成目录当中,我们会看到是这样的目录结构: 嗯,自动生成固然是简单,但是在html当中,却没有一个合适的标签来去做.今天后台导出PDF的时候告诉我,他需要用html做一个这样的结构, ...
- 自动生成百度小程序sitemap.txt文件路径
因为业务需要,需要在目前项目上开发一个百度小程序,百度智能小程序上线了,但是内容每天得推送,不可能一个小程序路径一个推送吧,因为小程序路径和项目路径不一致. 因为项目是用ThinkPHP开发的,在此附 ...
- 使用LaTeX和KnitR自动生成报告
扩展名为.Rnw(Rtex)的文件就是包含了R代码的LaTeX文档.编译的时候,先用Rscript调用Knitr处理,生成.TeX文档,然后用pdfLaTeX/XeLaTeX编译成PDF. 最方便的编 ...
- 写了个自动生成vcxproj的程序
背景: 公司的vcxproj有个模板,必须要遵守 程序测试 config = { { ProjName = 'my_exe', ClCompile = {'main.cpp', 'main2.cpp' ...
随机推荐
- jenkins的搭建
根据官方网站的步骤进行安装 网址:https://wiki.jenkins.io/display/JENKINS/Installing+Jenkins+on+Red+Hat+distributions ...
- word-break: break-word; 文本溢出
word-break: break-word; 中文汉字不会溢出,英文字母会溢出 这个时候添加属性 word-break: break-word; 即可 使得 不溢出 ======== ...
- Java学习笔记20(String类应用、StringBuffer类、StringBuilder类)
1.获取指定字符串中大小写和数字的个数: package demo; public class StringTest { public static void main(String[] args) ...
- Android异常分析(转)
关于异常 异常? 异常就是一种程序中没有预料到的问题,既然是没有预料到的,就可能不在原有逻辑处理范围内,脱离了代码控制,软件可能会出现各种奇怪的现象.比如:android系统常见异常现象有应用无响应. ...
- 【C#】发票助手二维码生成
之前一起吃饭听说了发票助手这个东西,可以生成发票抬头的二维码,扫码就可以开票了. 官方也有个小程序的 [税务发票助手],微信中搜这个名字就可以了. 我准备在自己的小程序中也尝试一下,本来觉得只要拼接一 ...
- ComboBox 中 DisplayMember 和 ValueMember 都是具体干什么的?
ComboBox组件的数据绑定,在得到数据集后,只有设定好ComboBox组件的的三个属性就可以完成数据绑定了,这三个属性是:"DisplayMember". "Valu ...
- ABP Zero 导航菜单之角色权限
本文的项目是官网生成,项目名称为XX,WEB为MVC,以Users权限模块为例解说文章. 1.定义PermissionNames PermissionNames是一个静态类,它在/XX.Core/Au ...
- 七牛php-sdk使用-文档处理
所用到的七牛文档转换服务,主要是:ppt文件转为pdf文件,pdf文件转图片(png). 描述一下需求:上传PPT或者PDF文件到七牛,最终转换为图片.文件上传部分的功能已经讲过了,这里说一下转换处理 ...
- Inno Setup 自定义界面心得
因为项目需要,需要打 windows 安装包,要求安装界面完全按照需求来.作为没接触过这块儿的服务端宝宝,在此期间踩了很多坑. 坑不提也罢,最终结果圆满,记录下与大部分网上PO出来的做法不太一样的小心 ...
- springboot之集成mybatis mongo shiro druid redis jsp
闲来无事,研究一下spingboot 发现好多地方都不一样了,第一个就是官方默认不支持jsp 于是开始狂找资料 终于让我找到了 首先引入依赖如下: <!-- tomcat的支持.--> ...