Word自定义导出小记(二)_ 多级DataTable导出 _C#

继续记录今天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);
    }
 }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值