c#生成word报告

有个WPF做的客户端在完成任务后需要出具一份受控报告,详情如下。

目的:根据word模板结合具体数据生成word报告
技术路径:word模板包含书签,生成报告时具体数据替换对应的书签,书签类型有字符串和表格两种。
需求
○ 能够将word书签替换为字符串、表格;
○添加页脚:能够获取当前页面页数,以及总页数

c#生成word报告_第1张图片
现有c# word库调研:
c#生成word报告_第2张图片
综上,优先推荐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报告。
c#生成word报告_第3张图片

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仅供参考,直接复制肯定跑不通

参考

NPOI.XWPF允许用户操作.docx格式
Aspose.Words for .NET(无需依赖第三方应用,例如Microsoft Word, 或Office Automation,但是收费,慎用!)
Spire.Doc for .NET(收费)
c# Library for manipulating Word documents

你可能感兴趣的:(C#,c#,word,microsoft,WPF,wpf)