C#操作 Word 书签模板
C#操作 Word 书签模板
一制作模板
1 新建一个文档,设置文档内容。对于循环的部分,建议放到表格内,这样容易定位、选择、
复制、粘贴。
2 将鼠标定位到要插入书签的位置,从菜单上,“插入”->“书签”,弹出对话框,输入书签
名,点击“添加”按钮。
插入以下书签:order_num,报告日期_,报表模板__,name,age,结论__
其中,报表模板__,用于定位模板表格。可有可无,没有时,默认表格 1。
完成后,所有书签的名称和位置如下图所示:
3 保存模板,比如“word 书签模板.doc”
二 添加引用
1 右击“解决方案资源管理器”中的项目目录下的“引用”,选择“添加引用”,打开“添加
引用”对话框
2 对于 WindowsForm 方式时,在“添加引用”-->“COM”-->“Microsoft Word 11.0 Object Library”,
点击“确定”
3 对于 WebSite 网站方式时,打开“添加引用”-->“浏览”项-->”Microsoft.Office.Interop.Word.dll”
文件,选中它,点击“确定”
注意:此处要查找的“Microsoft.Office.Interop.Word.dll”版本必须为“11.*.*.*”,“*”代表
数字
以上版本对应是 Office Word 2003 版本。
三 编译执行
如 果 编 译 时 产 生 错 误
CS1752: 无 法 嵌 入 互 操 作 类 型
“Microsoft.Office.Interop.Word.ApplicationClass”。请改用适用的接口。
,那么,点击 “解决方案”下“工程名称”之下的“引用”之下的 Word,在其属性下,将
“潜入互操作类型”,由 true 改为 false 即可。
运行结过如下:
四 主要的代码如下:
1 首先引用(WindowsForm):Microsoft Word 11.0 Object Library
或者引用(WebSite):Microsoft.Office.Interop.Word.dll
2 在使用的程序中,加入以下语句
using Word = Microsoft.Office.Interop.Word;
===== 1 主操作界面代码 ===
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Word = Microsoft.Office.Interop.Word;
using word_namespace;
namespace winFormApp_word_bookmark
{
public partial class Form1 : Form
{
private object missing = System.Reflection.Missing.Value;
WordHelper wdHelp;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
wdHelp = new WordHelper();
wdHelp.CreateOneDocument("c:\\ii.doc", missing, missing, missing);
//1 这里简单生成样例数据表,工作中要以实际的数据集为准
DataTable dt = new DataTable();
dt.Columns.Add("name", typeof(string));
dt.Columns.Add("age", typeof(int));
DataRow dr = dt.NewRow();
dr["name"] = "张三"; dr["age"] = 20;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["name"] = "李四"; dr["age"] = 25;
dt.Rows.Add(dr);
//2 调用模板替换函数,生成实际的数据
SetNameCellValue(dt);
wdHelp.SaveAs("c:\\bb.doc");
wdHelp.Close();
MessageBox.Show("ok");
}
public void SetNameCellValue(DataTable dt)
{
//(一) 这里设置表头的项目,比如报表日期
//特别注意:为了容易起见,命名单元格的规则如下,注意:word 中书签不能以下划
线开头,可能是保留的书签使用
//1.1 开头处的命名单元格,以 1 个下划线结尾,比如,报告日期_
//1.2 中间循环命名单元格,就是正常的,与数据集的字段名一致为好
//1.3 结尾处的命名单元格,以 2 个下划线结尾,比如,合计__
try
{//为了程序自动处理方便起见
wdHelp.GoToBookMark("报告日期_");//开始处的命名单元格,都以 1 个下划线_结尾
wdHelp.InsertText(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
}
catch (System.Exception ex)
{
}
//(二) 根据数据源的个数,设置重复变化的数据行组,
//1 声明与命名单元格相关的变量和数组
int min_Row = 65536, min_Col = 65536, max_Row = 0;
string min_Name = "";
int nameCellCount = wdHelp.wordDoc.Bookmarks.Count;//获得命名单元格的总数
int[] nameCellRow = new int[nameCellCount];//某个命名单元格的行
int[] nameCellColumn = new int[nameCellCount];//某个命名单元格的列
string[] nameCellTag = new string[nameCellCount];//某个命名单元格的常规地址 ,比如
$A$1
string[] nameCellName = new string[nameCellCount];//某个命名单元格的自定义名称,
比如 工资
string strName, str;
int row1, row2;//选择重复的行
int nameCellIdx = 0;
Word.Range tmpRange,srcRange,desRange;
//2 寻找所有命名的单元格,并找到行号最小者,以便在它之前插入循环行
for (int k = 0; k < nameCellCount; k++)
{
strName = wdHelp.wordDoc.Bookmarks[k + 1].Name;//
str = strName.Substring(strName.Length - 1, 1);
if (str == "_")
{
continue;//如果第一个字符为下划线,则认为是固定命名单元格,不是命名的循
环单元格
}
try
{
tmpRange = wdHelp.wordDoc.Bookmarks.get_Item(strName).Range;
nameCellColumn[nameCellIdx] = tmpRange.Cells[1].ColumnIndex;//
app.ActiveCell.Column;
nameCellRow[nameCellIdx] = tmpRange.Cells[1].RowIndex;//app.ActiveCell.Row;
nameCellName[nameCellIdx] = strName;
nameCellTag[nameCellIdx] = "";// app.ActiveCell.Address;//$A$1
nameCellTag[nameCellIdx] = "";// nameCellTag[nameCellIdx].Split('$')[1];//$A$1--> A
if (min_Row > nameCellRow[nameCellIdx])
{
min_Row = nameCellRow[nameCellIdx];//最小的行号
min_Col = nameCellColumn[nameCellIdx];
min_Name = nameCellName[nameCellIdx];
}
nameCellRow[nameCellIdx]; ;//最大行号
nameCellIdx++;//真实的循环的命名单元格序号
if
(max_Row < nameCellRow[nameCellIdx]) max_Row =
}
catch (System.Exception ex)
{
}
}
nameCellCount = nameCellIdx;//实际要处理的循环的命名单元格数目
int loopRow = max_Row - min_Row + 1;//一次循环的函数
//3 也 可 以 使 用 //foreach ( Word.Bookmark bk
in
wh.wordDoc.Bookmarks)MessageBox.Show(bk.Name);
Word.Table operTable;
// 方法 1 通常使用第一个表来作为模板表
operTable = wdHelp.wordDoc.Tables[1];
// 方法 2 使用一个书签来标志模板表
try
{//使用一个特殊的标签 table_bookmark_template_
tmpRange = wdHelp.wordDoc.Bookmarks.get_Item("报表模板__").Range;//
operTable = tmpRange.Tables[1];//得到该书签所在的表,以它为报表的循环模板
}
catch (System.Exception ex)
{
}
//
int template_start = 0;
int template_end = 0;
int table_columns=operTable.Columns.Count;//本表格的烈数
tmpRange = operTable.Cell(min_Row, 1).Range;
template_start =tmpRange.Start;//循环行组的第一行,第一个单元格,到文档开头的距
tmpRange = operTable.Cell(max_Row, table_columns).Range;
template_end = tmpRange.Start; //循环行组的最后行,最后一个单元格,到文档开头的
离
距离
srcRange = operTable.Cell(1, 1).Range;
desRange = operTable.Cell(1, 1).Range;
//4 根据数据集的实际数据行数,查找命名单元格,循环插入数据
int cur_row = min_Row;//0;// min_Row;//
for (int dt_row_idx = 0; dt_row_idx
{//循环实际的数据行数
//goto xx1;//跳过方法 1
//方法 1 整体多行组,复制和粘贴,看起来复杂
//4.1 找到行号最小的循环行组的命名单元格,以它来定位
tmpRange
=
wdHelp.wordDoc.Bookmarks.get_Item(min_Name).Range;//app.Goto(min_Name);
//4.2 //插入循环重复的摸板行组的行,使得所有命名单元格都向后移,以便下次循
环查找定位使用
app.ActiveCell.EntireRow.Insert();
// for (int j = 0; j < loopRow; j++)
// {//插入需要重复循环的行数 loopRow 的空行
//
// }
//4.3 定位到摸板行组首行
tmpRange = wdHelp.wordDoc.Bookmarks.get_Item(min_Name).Range;//转到摸板行组
的行号最小的命名单元格,以它来定位
row1 = tmpRange.Cells[1].RowIndex;//a //摸板行组的第一行
row2 = row1 + loopRow - 1; //摸板行组的最后一行
template_start = operTable.Cell(row1, 1).Range.Start;
//template_end = operTable.Cell(row2, table_columns).Range.Start;//这样少一列
template_end = operTable.Cell(row2+1, 1).Range.Start;//到下一行,第一个单元格
//4.4 复制整体模板的多行组,固定的摸板的格式和相关的文字说明,也可一个一
个单元格复制
srcRange.SetRange(template_start, template_end);//整体多行组复制摸板行组
srcRange.Copy();
//4.5 定位到新加入行的第一个单元格内
//row1 = row1 - loopRow;//向上回退到新加入的行组
//row2 = row2 - loopRow;
//4.6 粘贴整体多行组,固定的摸板的格式和相关的文字说明
desRange = operTable.Rows[row1].Range;//整体多行组粘贴摸板行组
desRange.Paste();
xx1: