您的位置:9159金沙官网 > www.9159.com > C# 处理Word自动生成报告 四、程序处理

C# 处理Word自动生成报告 四、程序处理

发布时间:2019-10-23 13:00编辑:www.9159.com浏览(188)

    C# 处理Word自动生成报告 四、程序处理。C# 处理Word自动生成报告 一、概述

    C#C# 处理Word自动生成报告 四、程序处理。 处理Word自动生成报告 二、数据源例子

    C#C# 处理Word自动生成报告 四、程序处理。 处理Word自动生成报告 三、设计模板

    C# 处理Word自动生成报告 四、程序处理

     

    现在说一下程序处理部分,有点长

    本来是想做针对doc和docx的模板两个版本, 后来想到可以在生成的时候saveas里设置格式,

    所以此版只支持对docx的模板处理,

    想要doc的情况可以选择生成格式为doc的.

    上代码:

    图片 1图片 2

     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>
            public bool CreateReport(string templateFile, DataSet dataSource, out string errorMsg, string newFilePath, ref string newFileName, int saveFormat = 16)
            {
                this.dataSource = dataSource;
                errorMsg = this.errorMsg;
                bool rtn = OpenTemplate(templateFile)
                    && SetContent(new WordElement(wordDoc.Range(), dataRow: dataSource.Tables[dataSource.Tables.Count - 1].Rows[0]))
                    && 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;
                string startWith = "loop_" + (element.Level + 1).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行;
                for (int i = 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)
            {
                if (element.Range.Bookmarks != null && element.Range.Bookmarks.Count > 0)
                {
                    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)
            {
                if (element.Range.Tables != null && element.Range.Tables.Count > 0)
                {
                    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); ;
    
                            if (config.SummaryRow > 0)
                            {
                                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);
                                for (int j = 0; j < table.Columns.Count; j++)
                                {
                                    newRow.Cells[j + 1].Range.Text = row[j].ToString(); ;
                                }
    
                            }
    
                            ((Word.Row)dataRowTemplate).Delete();
    
                            if (config.SummaryRow > 0 && SummaryDataRow != null)
                            {
                                for (int j = 0; j < SummaryRow.Cells.Count; j++)
                                {
                                    string temp = SummaryRow.Cells[j + 1].Range.Text.Trim().Replace("ra", "");
    
                                    if (!string.IsNullOrEmpty(temp) && temp.Length > 2 && dt.Columns.Contains(temp.Substring(1, temp.Length - 2)))
                                    {
                                        SummaryRow.Cells[j + 1].Range.Text = SummaryDataRow[temp.Substring(1, temp.Length - 2)].ToString();
                                    }
                                }
                            }
    
                            table.Title = tableElement.Name;
                        }
    
    
                    }
                }
    
                return true;
            }
            private bool SetChart(WordElement element)
            {
                if (element.Range.InlineShapes != null && element.Range.InlineShapes.Count > 0)
                {
                    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)
                            {
                                for (int i = chartElement.ColumnStart == -1 ? 0 : chartElement.ColumnStart - 1; i < (chartElement.ColumnEnd == -1 ? 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[1];
                            //设定范围  
                            string a = (chartElement.ColumnNameForHead ? rowsCount + 1 : rowsCount) + "|" + columnCount;
                            Console.WriteLine(a);
    
                            Excel.Range tRange = dataSheet.Range["A1", dataSheet.Cells[(chartElement.ColumnNameForHead ? rowsCount + 1 : rowsCount), columnCount]];
                            Excel.ListObject tbl1 = dataSheet.ListObjects[1];
                            //dataSheet.ListObjects[1].Delete(); //想过重新删除再添加  这样 原有数据清掉了, 但觉得性能应该会有所下降
                            //Excel.ListObject tbl1 = dataSheet.ListObjects.AddEx();
                            tbl1.Resize(tRange);
                            for (int j = 0; j < rowsCount; j++)
                            {
                                DataRow row = dataRows[j];
                                for (int k = 0; k < columnCount; k++)
                                {
                                    dataSheet.Cells[j + 2, k + 1].FormulaR1C1 = row[columns[k]];
                                }
                            }
    
                            if (chartElement.ColumnNameForHead)
                            {
                                for (int k = 0; k < columns.Count; k++)
                                {
                                    dataSheet.Cells[1, k + 1].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;
            }
            private bool SaveFile(string newFilePath, ref string newFileName, int saveFormat = 16)
            {
                if (string.IsNullOrEmpty(newFileName))
                {
                    newFileName = DateTime.Now.ToString("yyyyMMddHHmmss");
    
                    switch (saveFormat)
                    {
                        case 0:// Word.WdSaveFormat.wdFormatDocument
                            newFileName += ".doc";
                            break;
                        case 16:// Word.WdSaveFormat.wdFormatDocumentDefault
                            newFileName += ".docx";
                            break;
                        case 17:// 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
        {
            public WordElement(Word.Range range, string elementName = "", DataRow dataRow = null, Dictionary<string, string> groupBy = null, int tableIndex = 0)
            {
                this.Range = range;
                this.ElementName = elementName;
                this.GroupBy = groupBy;
                this.DataRow = dataRow;
                if (string.IsNullOrEmpty(elementName))
                {
                    this.Level = 0;
                    this.TableIndex = tableIndex;
                    this.Name = string.Empty;
                    this.ColumnNameForHead = false;
                }
                else
                {
                    string[] element = elementName.Split('_');
                    this.Level = int.Parse(element[1]);
                    this.ColumnNameForHead = false;
                    this.ColumnStart = -1;
                    this.ColumnEnd = -1;
    
                    if (element[0].Equals("label"))
                    {
                        this.Name = element[2];
                        this.TableIndex = 0;
                    }
                    else
                    {
                        this.Name = element[4];
                        this.TableIndex = int.Parse(element[2]) - 1;
    
                        if (!string.IsNullOrEmpty(element[3]))
                        {
                            string[] filters = element[3].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());
                                }
    
                            }
                        }
    
                        if (element[0].Equals("chart") && element.Count() > 5)
                        {
                            this.ColumnNameForHead = element[5].Equals("1");
                            this.ColumnStart = string.IsNullOrEmpty(element[6]) ? -1 : int.Parse(element[6]);
                            this.ColumnEnd = string.IsNullOrEmpty(element[7]) ? -1 : int.Parse(element[7]);
                        }
                    }
                }
            }
    
            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
                {
                    if (GroupBy == null || GroupBy.Count == 0)
                    {
                        return string.Empty;
                    }
    
                    string rtn = string.Empty;
                    foreach (string key in this.GroupBy.Keys)
                    {
                        rtn += "and " + key + " = '" + GroupBy[key] + "' ";
                    }
                    return rtn.Substring(3);
                }
            }
    
            public static string GetName(string elementName)
            {
                string[] element = elementName.Split('_');
    
    
                if (element[0].Equals("label"))
                {
                    return element[2];
                }
                else
                {
                    return element[4];
                }
            }
        }
    
        public class TableConfig
        {
            public TableConfig(string tableDescr = "")
            {
                this.DataRow = 2;
                this.SummaryRow = -1;
    
                if (!string.IsNullOrEmpty(tableDescr))
                {
                    string[] element = tableDescr.Split(',');
                    foreach (string item in element)
                    {
                        if (!string.IsNullOrEmpty(item))
                        {
                            string[] configs = item.Split(':');
                            if (configs.Length == 2)
                            {
                                switch (configs[0].ToLower())
                                {
                                    case "data":
                                    case "d":
                                        this.DataRow = int.Parse(configs[1]);
                                        break;
                                    case "summary":
                                    case "s":
                                        this.SummaryRow = int.Parse(configs[1]);
                                        break;
                                    case "summaryfilter":
                                    case "sf":
                                        this.SummaryFilter = configs[1];
                                        break;
                                    default:
                                        break;
                                }
                            }
                        }
                    }
                }
    
            }
            public int DataRow { get; set; }
            public int SummaryRow { get; set; }
            public string SummaryFilter { get; set; }
        }
    

    View Code

     

    后续问题: 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, 希望能完美解决上面的问题.

    本文由9159金沙官网发布于www.9159.com,转载请注明出处:C# 处理Word自动生成报告 四、程序处理

    关键词: