OpenXml 合并单元格并在书签处插入表格

在日常开放中经常会遇到各种操作word中的表格问题,或者基于word模板生成word等等操作。微软得com组件挺好但是必须要安装office对于客户来说很麻烦,而且效率很慢。推荐使用openxml~,但是使用openxml比较烦,各种操作繁琐,但相对与com组件无需安装,速度快就是它得优势~以下代码

/// 
        /// 生成表格
        /// 
        /// 
        /// 
        /// 
        public Table GetParagraph(OpenxmlTableModel reportTable, Int32Value width)
        {
            Table table = new Table();
            TableProperties tblProp = new TableProperties(
                new TableBorders(
                    new TopBorder() { Val = new EnumValue(BorderValues.Single), Size = 4 },
                    new BottomBorder() { Val = new EnumValue(BorderValues.Single), Size = 4 },
                    new LeftBorder() { Val = new EnumValue(BorderValues.Single), Size = 4 },
                    new RightBorder() { Val = new EnumValue(BorderValues.Single), Size = 4 },
                    new InsideHorizontalBorder() { Val = new EnumValue(BorderValues.Single), Size = 4 },
                    new InsideVerticalBorder() { Val = new EnumValue(BorderValues.Single), Size = 4 }
                 )
            )
            {
                //A4表格 4835左右
                TableWidth = new TableWidth() { Width = width.ToString(), Type = TableWidthUnitValues.Pct },
            };
            table.Append(tblProp);
            int cols = reportTable.Column;
            int j = 0;
            foreach (List strs in reportTable.Value)
            {
                int merge = 0;
                bool startMerge = true;
                TableRow row = new TableRow();
                for (int i = 0; i < cols; i++)
                {
                    merge = merge > 0 ? merge : strs[i].Merges;
                    TableCell cell = new TableCell();
                    //单元格属性
                    TableCellProperties tableCellProperties = new TableCellProperties();
                    //段落属性
                    Paragraph par = new Paragraph();
                    //边距
                    TableCellMargin margin = new TableCellMargin
                    {
                        LeftMargin = new LeftMargin() { Width = "0", Type = TableWidthUnitValues.Auto },
                        RightMargin = new RightMargin() { Width = "0", Type = TableWidthUnitValues.Auto }
                    };
                    tableCellProperties.Append(margin);
                    //垂直居中,将属性加入到单元格样式段落样式
                    tableCellProperties.Append(new TableCellVerticalAlignment { Val = TableVerticalAlignmentValues.Center });
                    par.Append(new ParagraphProperties(new Justification() { Val = JustificationValues.Center }));
                    Run run = new Run();
                    //表头
                    if (j == 0 && reportTable.IsHaveHeader)
                    {
                        RunProperties rPr = new RunProperties();
                        rPr.Append(new RunFonts() { EastAsia = "微软雅黑" });
                        rPr.Append(new FontSize() { Val = "28" });
                        if (reportTable.IsHaveHeaderBold)
                            rPr.Append(new Bold());
                        run.Append(rPr);
                    }
                    //数据
                    if (merge > 0)
                    {
                        HorizontalMerge verticalMerge = new HorizontalMerge();
                        //开始合并
                        if (startMerge)
                        {
                            RunProperties rPr = new RunProperties();
                            //rPr.Append(new Bold());
                            rPr.Append(new RunFonts() { EastAsia = "微软雅黑" });
                            rPr.Append(new FontSize() { Val = "26" });
                            run.Append(rPr);
                            verticalMerge.Val = MergedCellValues.Restart;
                            run.Append(CreateText(strs[i].StrValue));
                            startMerge = false;
                        }
                        else
                        {
                            verticalMerge.Val = MergedCellValues.Continue;
                            merge--;
                            if (merge == 0)
                                startMerge = true;
                        }
                        tableCellProperties.Append(verticalMerge);
                    }
                    else
                    {
                        RunProperties rPr = new RunProperties();
                        rPr.Append(new RunFonts() { EastAsia = "微软雅黑" });
                        rPr.Append(new FontSize() { Val = "26" });
                        run.Append(rPr);
                        run.Append(CreateText(strs[i].StrValue));
                    }
                    par.Append(run);
                    cell.Append(tableCellProperties);
                    cell.Append(par);
                    row.Append(cell);
                }
                j++;
                table.Append(row);
            }

            return table;
        }

        private Text CreateText(string text)
        {
            if (text == null)
                text = string.Empty;
            Text t = new Text(text);
            if (text.EndsWith(" "))
            {
                t.Space = new EnumValue(SpaceProcessingModeValues.Preserve);
            }
            if (text.StartsWith(" "))
            {
                t.Space = new EnumValue(SpaceProcessingModeValues.Default);
            }
            return t;
        }

经过我计算,表格宽度大概在4835左右适合A4纸张。Model如下

#region Identity

        /// 
        /// openxml生成word表格
        /// 
        public class OpenxmlTableModel
        {
            public List> Value { get; set; }
            /// 
            /// 表格列
            /// 
            public int Column { get; set; }
            /// 
            /// 是否有表头
            /// 
            public bool IsHaveHeader { get; set; } = false;
            /// 
            /// 表头加粗
            /// 
            public bool IsHaveHeaderBold { get; set; } = false;

            public class StrText
            {
                /// 
                /// 文本
                /// 
                public string StrValue { get; set; }
                /// 
                /// 合并行
                /// 
                public int Merges { get; set; } = 0;
            }
        }
        #endregion

OpenxmlTableModel一共有几个参,一个List类,里面存放所有得数据,第一行是否为表头,表头是否加粗。

StrText两个参数,内容(默认占据一个单元格),Merges占据几个单元格(默认0即一个单元格)

TODO:讲一讲GetParagraph这个函数的合并实现(另外一些字体设置参见代码)

在word中生成Table并合并单元格需要使用到HorizontalMerge横向合并或者VerticalMerge纵向合并(命名空间:DocumentFormat.OpenXml.Wordprocessing)不是来自于Excel,请注意。参照官方文档 微软文档 。官方也有一个合并的文档,今天找不到了~

查看MergedCellValues.Restart的注释可以知道“Start/Restart Merged Region.When the item is serialized out as xml, its value is "restart".”设置开始合并的位置或者重新设置。简单点,就是标记从这个单元格开始。MergedCellValues.Continue从上一个点开始继续合并。

我在代码中是这样实现的:该单元格的Merges大于0,开始合并,标记startMergetrue,结束标记为false,同时用一个变量接收合并单元格的数量,依次减1,Merges为0的时候重启startMergetrue

以下调用例子

//构造数据
                //表头
                var openxmlModel = new OperationWordHelper.OpenxmlTableModel()
                {
                    Column = 6,
                    IsHaveHeader = true,
                    IsHaveHeaderBold = true,
                    Value = new List>()
                    {
                        new List()
                        {
                            new OperationWordHelper.OpenxmlTableModel.StrText()
                            {
                                StrValue="项目"
                            },
                            new OperationWordHelper.OpenxmlTableModel.StrText()
                            {
                                StrValue="型号"
                            },
                            new OperationWordHelper.OpenxmlTableModel.StrText()
                            {
                                StrValue="单价(元)"
                            },
                            new OperationWordHelper.OpenxmlTableModel.StrText()
                            {
                                StrValue="数量"
                            },
                            new OperationWordHelper.OpenxmlTableModel.StrText()
                            {
                                StrValue="小计(元)"
                            },
                            new OperationWordHelper.OpenxmlTableModel.StrText()
                            {
                                StrValue="备注"
                            },
                        },
                    }
                };
                //数据
                foreach (var item in quos.Goodss)
                {
                    openxmlModel.Value.Add(new List()
                    {
                        new OperationWordHelper.OpenxmlTableModel.StrText()
                        {
                            StrValue=item.Name
                        },
                        new OperationWordHelper.OpenxmlTableModel.StrText()
                        {
                            StrValue=item.Spec
                        },
                        new OperationWordHelper.OpenxmlTableModel.StrText()
                        {
                            StrValue=item.UnitPrice.ToString("f2")
                        },
                        new OperationWordHelper.OpenxmlTableModel.StrText()
                        {
                            StrValue=item.Quantity.ToString()
                        },
                        new OperationWordHelper.OpenxmlTableModel.StrText()
                        {
                            StrValue=(item.Quantity*item.UnitPrice).ToString("f2")
                        },
                        new OperationWordHelper.OpenxmlTableModel.StrText()
                        {
                            StrValue=item.Remarks
                        },
                    });
                }
                //总价
                openxmlModel.Value.Add(new List()
                {
                    new OperationWordHelper.OpenxmlTableModel.StrText()
                    {
                        StrValue="合计",
                        Merges=3
                    },
                    new OperationWordHelper.OpenxmlTableModel.StrText()
                    {
                        StrValue="",
                        Merges=0
                    },
                    new OperationWordHelper.OpenxmlTableModel.StrText()
                    {
                        StrValue="",
                        Merges=0
                    },
                    new OperationWordHelper.OpenxmlTableModel.StrText()
                    {
                        StrValue="",
                        Merges=0
                    },
                    new OperationWordHelper.OpenxmlTableModel.StrText()
                    {
                        StrValue=quos.Goodss.Sum(t=>t.UnitPrice*t.Quantity).ToString("f2")
                    },
                    new OperationWordHelper.OpenxmlTableModel.StrText()
                    {
                        StrValue=""
                    },
                });
                //折扣后总价
                var goodsCharge = quos.Goodss.Sum(s => s.UnitPrice * s.Quantity);  //物品费用合计
                var outsourceCharge = quos.Goodss.Where(s => s.Outsource).Sum(s => s.UnitPrice * s.Quantity); //外协费用
                var totalCharge = goodsCharge + quos.MaintenanceCharge + quos.ServiceCharge + quos.TravelCharge; //折前费用
                var discountedCharge = totalCharge * quos.DiscountRate; //折后费用
                openxmlModel.Value.Add(new List()
                {
                    new OperationWordHelper.OpenxmlTableModel.StrText()
                    {
                        StrValue="折扣后合计",
                        Merges=3
                    },
                    new OperationWordHelper.OpenxmlTableModel.StrText()
                    {
                        StrValue="",
                        Merges=0
                    },
                    new OperationWordHelper.OpenxmlTableModel.StrText()
                    {
                        StrValue=""
                    },
                    new OperationWordHelper.OpenxmlTableModel.StrText()
                    {
                        StrValue=""
                    },
                    new OperationWordHelper.OpenxmlTableModel.StrText()
                    {
                        //总价减去折扣费用
                        StrValue = discountedCharge?.ToString("f2")
                    },
                    new OperationWordHelper.OpenxmlTableModel.StrText()
                    {
                        StrValue = NumToChinese.NumtoChinese((decimal)discountedCharge)
                    },
                });

生成效果如下:OpenXml 合并单元格并在书签处插入表格_第1张图片

多列合并如下:

new List()
            //            {
            //                new StrText()
            //                {
            //                    StrValue="合并内容1",
            //                    Merges=1
            //                },
            //                new StrText()
            //                {
            //                    StrValue="",
            //                    Merges=0
            //                },
            //                new StrText()
            //                {
            //                    StrValue="合并内容2",
            //                    Merges=2
            //                },
            //                new StrText()
            //                {
            //                    StrValue="合并内容2",
            //                    Merges=0
            //                },
            //                new StrText()
            //                {
            //                    StrValue="合并内容2",
            //                    Merges=0
            //                },
            //            },

将会呈现两列,第一个单元格占据两列,第二个占据三列

参考https://www.cnblogs.com/zhouxin/p/3174936.html

你可能感兴趣的:(C#,.Net,Core,.NET,MVC)