继续记录今天C#环境,NPOI导出Word遇到的问题
1、树状DataTable导出,行混乱
解决办法,建一个Rows标识控制
XWPFTableRow row = table.InsertNewTableRow(rows);//插入行
rows++;//插一行 跳一行,循环不出错
2、单元格 改字体、文字大小
public static XWPFParagraph SetCell(XWPFDocument doc, XWPFTable table, string setText)
{
//table中的文字格式设置
var para = new CT_P();
var Paragraph= new XWPFParagraph(para, table.Body);//单元格
Paragraph.VerticalAlignment = TextAlignment.CENTER; //--字体居中
var run = Paragraph.CreateRun();//单元格文本
run.SetText(setText);
run.FontSize = 11;
run.SetFontFamily("仿宋", FontCharRange.None); //设置字体
return Paragraph;
}
调用:
Cell.SetParagraph(SetCell(doc, table, "显示文字"));//写入单元格
3、表格单元格 背景颜色
Paragraph.FillBackgroundColor = "#000000";
段落设置,没效果
run.SetColor("#000000");
文本设置,这个是字体颜色,也达不到效果
解决办法:
cell.SetColor("#000000");//插入行的时候 加背景色
没想到样式要加到单元格上。
4、文本行高
foreach (XWPFParagraph p in doc.Paragraphs)
{
p.SpacingBetween = 1.1; // 110% 行高
}
在doc.Write之前,批执行一下,有点间距就行。
5、单元格行高
row.Height = 400;//行高
单元格,就是table里面的格,跟上一条的段落行高不一样哈
6、单元格垂直居中
Paragraph.Alignment = ParagraphAlignment.CENTER; //--字体居中
加段落上也不生效
cell.SetVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);//垂直居中
加单元格上,搞定
7、图片替换占位符,多table分布
if (parameter.Key.Contains("img"))
{
//假如 占位符[comimg] 字典对应value=url,width,height
string str[]=value.split(",");
using (FileStream imgstream = new FileStream(str[0], FileMode.Open, FileAccess.Read))//打开图
{
bool isget = false;
doc.Tables.ToList().ForEach(table => //循环表
{
if (isget) return;
table.Rows.ToList().ForEach(Row => //循环列
{
if (isget) return;
Row.GetTableCells().ToList().ForEach(Cell => //循环单元格
{
if (isget) return;
if (Cell.GetText().Contains(parameter.Key))//包含占位符
{
XWPFParagraph par = Cell.Paragraphs[0]; //获单元格段落
par.ReplaceText("[" + parameter.Key + "]", null);//去掉占位符
var widthPic = (int)((double)str[1]* 10000);
var heightPic = (int)((double)str[2]* 10000);
par.InsertNewRun(0).AddPicture(imgstream, (int)NPOI.XWPF.UserModel.PictureType.PNG, "img", widthPic, heightPic);//写入图片
isget = true;//lambda下的ForEach 跳不出去,只有出此下策
return;
}
});
});
});
}
}
比如Logo、案例图、产品、广告图等,不在段落、而在表格,且分布于多个表格。
如果是段落内的图 var search = doc.Paragraphs.Where(p => p.Text.Contains(parameter.Key));即可。
但表格内的图必须,多层获取 表格->行->单元格 cell.Paragraphs 才能进行同样的操作。
8、归纳一下
public class Export
{
public static int lineheight = 400;
/// <summary>
/// 导出入口
/// </summary>
public static bool Main(string templePath, string outPath, Dictionary<string, string> parameters
, DataTable dtmenu, DataTable dtdata)
{
using (FileStream stream = File.OpenRead(templePath))
{
try
{
XWPFDocument doc = new XWPFDocument(stream);
//表格 排版
ProsLayout(dtmenu, dtdata, doc);
//模板占位符 替换
TextReplace(parameters, doc);
//设置行高
foreach (XWPFParagraph p in doc.Paragraphs)
{
p.SpacingBetween = 1.1; // 110% 行高
}
//写文件
FileStream outFile = new FileStream(outPath, FileMode.Create);
doc.Write(outFile);
outFile.Close();
WordToPDF(outPath);//同步导出pdf
return true;
}
catch (Exception ex)
{
return false;
}
}
}
/// <summary>
/// 多级dt排版
/// </summary>
private static void DataLayout(DataTable dtmenu, DataTable dt, XWPFDocument doc)
{
var table = doc.Tables[1];//使用现有表
int columns = table.GetRow(0).GetTableCells().Count;//列数
int rows = 1;//第几行
//-------------------------------1级循环--菜单------------------------------
for (int i = 0; i < dtmenu.Rows.Count; i++)//dtmenu 是id-name两列的DataTable
{
XWPFTableRow row = NewRow(); //插入行 并初始化单元格
row.MergeCells(0, columns - 1);//整行合并为1格
//行赋值
string menustr = dtmenu.Rows[i]["name"].ToString();
row.GetCell(0).SetParagraph(SetCellTh(doc, bomTable, menustr));
row.GetCell(0).SetColor("#D9D9D9");//改背景色 作为菜单行,背景颜色深一点很合理,对吧
rows++;//插一行,跳一行。
//子查询 下一级筛选数据
string menuid = (dtmenu.Rows[i]["id"]).ToString().Trim(); //
var dxt= dtdata.AsEnumerable().Where(p => p["menuid"].ToString()== menuid);
if (dxt.ToList().Count == 0) continue;//无子项 跳过本次循环
var _dt = dxt.CopyToDataTable();//筛选结果 转 datatable格式
//-------------------------------2级循环--内容------------------------------
for (int k = 0; k < _dt.Rows.Count; k++) //内容数据
{
//插入子行
XWPFTableRow row_son = NewRow();//插入行 并初始化单元格
//子行赋值
for (int j = 0; j < columns; j++)
{
string str = _dt.Rows[k][j].ToString();
if (j == 0) str = (k + 1).ToString();//第一列 序号
else
row_son.GetCell(j).SetParagraph(SetCellTh(doc, bomTable, str));//dt 数据循环进 单元格
}
rows++;//子行也是要跳行的。
//--还有下一级继续在这for
}
//-------------------------------2级循环--end------------------------------
}
}
/// <summary>
/// 单元格赋值、样式
/// </summary>
public static XWPFParagraph SetCell(XWPFDocument doc, XWPFTable table, string setText)
{
//table中的文字格式设置
var para = new CT_P();
var Paragraph= new XWPFParagraph(para, table.Body);//创建单元格
//Paragraph.Alignment = ParagraphAlignment.CENTER; //--不生效 所以注释了
Paragraph.VerticalAlignment = TextAlignment.CENTER; //--字体居中
var run = Paragraph.CreateRun();//创建单元格文本
run.SetText(setText);
run.FontSize = 11;
run.SetFontFamily("仿宋", FontCharRange.None); //设置字体
return Paragraph;
}
/// <summary>
/// 新建行 并初始化单元格
/// </summary>
private static XWPFTableRow NewRow(XWPFTable table, int columns, int rows)
{
XWPFTableRow row = table.InsertNewTableRow(rows);//插入行
row.Height = lineheight;//行高
//使用insertNewTableRow必须填充列,且列数必须统一
for (int j = 0; j < columns; j++)
{
row.CreateCell(); //创建列
row.GetCell(j).SetVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);//垂直居中
}
return row;
}
/// <summary>
/// word转PDF
/// </summary>
public static bool WordToPDF(string sourcePath)
{
//要using Microsoft.Office.Interop.Word;
bool result = false;
Microsoft.Office.Interop.Word.Application application = new Microsoft.Office.Interop.Word.Application();
Microsoft.Office.Interop.Word.Document document = null;
try
{
application.Visible = false;
document = application.Documents.Open(sourcePath);//打开文件
string PDFPath = sourcePath.Replace(".docx", ".pdf");//pdf存放位置
if (!File.Exists(@PDFPath))//存在PDF,不需要继续转换
{
document.ExportAsFixedFormat(PDFPath, Microsoft.Office.Interop.Word.WdExportFormat.wdExportFormatPDF);
}
document.Close();//回收
result = true;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
result = false;
}
return result;
}
/// <summary>
/// 占位符 替换
/// </summary>
private static void TextReplace(Dictionary<string, string> parameters, XWPFDocument doc)
{
foreach (var parameter in parameters)
{
string str = parameter.Value;
//时间占位符,替换换格式
if (parameter.Key.Contains("time"))
{
str = DateTime.Parse(str.ToString()).ToString("yyyy-MM-dd");
doc.FindAndReplaceText("[" + parameter.Key + "]", str);
}
//图标替换占位符
else if (parameter.Key.Contains("img"))
{
using (FileStream imgstream = new FileStream(str, FileMode.Open, FileAccess.Read))//打开图
{
bool isget = false;
doc.Tables.ToList().ForEach(table => //循环表
{
if (isget) return;
table.Rows.ToList().ForEach(Row => //循环列
{
if (isget) return;
Row.GetTableCells().ToList().ForEach(Cell => //循环单元格
{
if (isget) return;
if (Cell.GetText().Contains(parameter.Key))//包含占位符
{
XWPFParagraph par = Cell.Paragraphs[0]; //获单元格段落
par.ReplaceText("[" + parameter.Key + "]", null);//去掉占位符
var widthPic = (int)((double)100 * 10000);
var heightPic = (int)((double)50 * 10000);
par.InsertNewRun(0).AddPicture(imgstream, (int)NPOI.XWPF.UserModel.PictureType.PNG, "img", widthPic, heightPic);//写入图片
isget = true;
return;
}
});
});
});
}
}
//富文本占位符,替换 手动换行
else if (parameter.Key.Contains("notes"))
{
//找到段落
var search = doc.Paragraphs.Where(p => p.Text.Contains(parameter.Key)).First();
//创建文本对象
var run = search.CreateRun();
//移除占位
search.ReplaceText("[" + parameter.Key + "]", "");
//手动换行
string[] strs = str.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
strs.ToList().ForEach(p =>
{
run.AppendText(p);//写入内容
run.AddCarriageReturn();//加回车
});
run.FontSize = 11;
run.FontFamily = "仿宋";
}
//普通占位符 字符串替换
else
doc.FindAndReplaceText("[" + parameter.Key + "]", str);
}
}
}