Excel导出报表学习

  报表特别多的业务逻辑,还是做成一个电子政务、文件管理系统比较合适。比如煤矿的储量管理,就针对报表!和OA系统很类似啊!有些侧重信息管理如地质信息,水文信息,当然也有报表,但是相对来说就少的多了!还是做成信息管理系统,用数据库比较好!对于煤矿机电设备设施管理不好说,感觉各有利弊!

今天重新拾起用Excel输出报表的工作。别人封装的来实在是看不懂!

  基本思路:任何一个报表都可以划分成若干区域,如图的课程表用红色框划分成了7个区域。

  (似乎用树来组织会不错,如果能有个配置文件,能否不用编码就能实现任何报表的生成?)

  水晶报表的思想是报表包含子报表。如果类比这种思想报表->子报表->区域,那么区域就是输出报表的最小单位。区域包含一系列相同的特性:边框、对齐方式、颜色、字体。区域的确定通过左上角点Cell和行列数目。运用Excel自带的互操作集,划分的区域可以再次划分,如7区域可以再进一步划分,Range可以支持反复的写入。这里只是初步实现了基本功能,区域包含的属性包括:起始xlsCell、行数、列数、object[,]数据、对齐方式、边框(是一个16进制的整数值)、字体、颜色、单元宽度、单元格行高等属性。

目前的类关系是区域(父类)<--标题类,如果使用多工厂方法模式或者简单工厂模式,似乎可以,把区域作为抽象,不过似乎有没有那个必要。再考虑吧。

区域定义如下:

报表区域类
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using Excel=Microsoft.Office.Interop.Excel;
  6 using System.Reflection;
  7 namespace NtExcel
  8 {
  9     
 10     public class xlsRegion
 11     {
 12         public const uint Grid_InsideHorizontal = 0x0001;
 13         public const uint Grid_InsideVertical = 0x0002;
 14         public const uint Grid_EdgeTop = 0x0004;
 15         public const uint Grid_EdgeBottom = 0x0008;
 16         public const uint Grid_EdgeLeft = 0x0010;
 17         public const uint Grid_EdgeRight = 0x0020;
 18 
 19 
 20         public static Excel._Application xlApp;
 21         public static Excel.Worksheet sheet;
 22 
 23         protected Excel.Range range;
 24         //起点单元格
 25         protected xlsCell startCell;
 26         //行数
 27         int nRowsCount = 0;
 28         public int RowsCount
 29         {
 30             get{return nRowsCount;}
 31             set{ nRowsCount=value;}
 32         }
 33         //列数
 34         int nColumnsCount = 0;
 35         public int ColumnsCount
 36         {
 37             get
 38             {
 39                 return nColumnsCount;
 40             }
 41             set { nColumnsCount = value; }
 42         }
 43         //合并单元格
 44         protected bool IsMergeCells;
 45         public bool MergeCells
 46         {
 47             get { return IsMergeCells; }
 48             set { IsMergeCells = value;}
 49         }
 50         //对齐方式
 51         Excel.Constants align;
 52 
 53         public Excel.Constants Alignment
 54         {
 55             get { return align; }
 56             set { align = value; }
 57         }
 58         //边框
 59         uint gridLine;
 60 
 61         public uint GridLine
 62         {
 63             get { return gridLine; }
 64             set { gridLine = value; }
 65         }
 66         //数据
 67         object[,] objdata;
 68 
 69         public object[,] Objdata
 70         {
 71             get { return objdata; }
 72             set { objdata = value; }
 73         }
 74         //构造函数
 75         public xlsRegion(xlsCell _startCell, int _RowCount, int _ColumnCount)
 76         {
 77             startCell = _startCell;
 78             int _endRowIndex = _startCell.RowIndex + _RowCount - 1;
 79             int _endColumnIndex = _startCell.ColumnIndex + _ColumnCount - 1;
 80             xlsCell endCell = new xlsCell(_endRowIndex, _endColumnIndex);//依赖值
 81             range = sheet.get_Range(xlApp.Cells[_startCell.RowIndex, startCell.ColumnIndex], xlApp.Cells[endCell.RowIndex, endCell.ColumnIndex]);
 82         }
 83         public xlsRegion(string strRange)
 84         {
 85             //正则表达式验证
 86             range = sheet.get_Range(strRange, Missing.Value);
 87         }
 88         public virtual void SetStyle()
 89         {
 90             //range.HorizontalAlignment = align;
 91             range.MergeCells = IsMergeCells;
 92             DrawGridLine();
 93         }
 94         protected void DrawGridLine()
 95         {
 96             if ((gridLine&Grid_InsideHorizontal)==Grid_InsideHorizontal)
 97             { range.Borders.get_Item(Excel.XlBordersIndex.xlInsideHorizontal).Weight = Excel.XlBorderWeight.xlThin;
 98             }
 99            if ((gridLine&Grid_InsideVertical)==Grid_InsideVertical)
100            {range.Borders.get_Item(Excel.XlBordersIndex.xlInsideVertical).Weight = Excel.XlBorderWeight.xlThin;
101            }
102             if ((gridLine&Grid_EdgeTop)==Grid_EdgeTop)
103             {range.Borders.get_Item(Excel.XlBordersIndex.xlEdgeTop).Weight = Excel.XlBorderWeight.xlThin;
104             }
105             if ((gridLine&Grid_EdgeBottom)==Grid_EdgeBottom)
106             {range.Borders.get_Item(Excel.XlBordersIndex.xlEdgeBottom).Weight = Excel.XlBorderWeight.xlThin;
107             }
108             if ((Grid_EdgeLeft&gridLine)==Grid_EdgeLeft)
109             {range.Borders.get_Item(Excel.XlBordersIndex.xlEdgeLeft).Weight = Excel.XlBorderWeight.xlThin;
110             }
111             if ((Grid_EdgeRight&gridLine)==Grid_EdgeRight)
112             {range.Borders.get_Item(Excel.XlBordersIndex.xlEdgeRight).Weight = Excel.XlBorderWeight.xlThin;
113             }
114             
115         }
116         public virtual void FillData()
117         {
118             range.Value2 = objdata;
119         }
120         
121     }
122 
123 }
xlsCell
 1 public class xlsCell
 2     {
 3         int nRowIndex;
 4 
 5         public int RowIndex
 6         {
 7             get { return nRowIndex; }
 8             set { nRowIndex = value; }
 9         }
10         int nColumnIndex;
11 
12         public int ColumnIndex
13         {
14             get { return nColumnIndex; }
15             set { nColumnIndex = value; }
16         }
17         public xlsCell(int _RowIndex, int _ColumnIndex)
18         {
19             nRowIndex = _RowIndex;
20             nColumnIndex = _ColumnIndex;
21         }
22        public  void MoveTo(int _RowIndex, int _ColumnIndex)
23        {
24             nRowIndex = _RowIndex;
25             nColumnIndex = _ColumnIndex;
26        }
27     }

为方便起见:从xlsRegion继承了标题类和列头类,图上1和3区域。

标题类
 1  public class xlsTitle: xlsRegion
 2     {
 3         public xlsTitle(xlsCell _startCell, int _cols)
 4            : base(_startCell, 1, _cols)
 5         {
 6             base.IsMergeCells = true;
 7             base.Alignment = Excel.Constants.xlCenter;
 8             base.GridLine = Grid_EdgeBottom | Grid_EdgeTop|Grid_EdgeLeft|Grid_EdgeRight;
 9         }
10         string title;
11 
12         public string Title
13         {
14             get { return title; }
15             set { title = value; }
16         }
17         public override void FillData()
18         {
19             range.Value2=title;
20         }
21         public override void SetStyle()
22         {
23             range.MergeCells = base.IsMergeCells;
24             range.HorizontalAlignment = base.Alignment;
25             base.DrawGridLine();
26         }
27     }
列头类
 1 public class xlsColumnHeader:xlsRegion
 2     {
 3         public xlsColumnHeader(xlsCell _startCell,int _ColumnsCount )
 4            : base(_startCell, 1, _ColumnsCount)
 5         {
 6             base.Alignment=Excel.Constants.xlCenter;
 7             base.GridLine=Grid_EdgeBottom|Grid_EdgeTop|Grid_EdgeLeft|Grid_EdgeRight;
 8         }
 9         List<string> headers;
10 
11         public List<string> Headers
12         {
13             get { return headers; }
14             set { headers = value; }
15         }
16         public override void FillData()
17         {
18             int i=0;
19             Excel.Range rg;
20             foreach (string str in headers)
21             {
22                 rg = xlApp.get_Range(xlApp.Cells[startCell.RowIndex, startCell.ColumnIndex+i], xlApp.Cells[startCell.RowIndex, startCell.ColumnIndex + i]);
23                 i++;
24                 rg.Value2 = str;
25             }
26            
27         }
28         public override void SetStyle()
29         {
30             range.MergeCells = base.IsMergeCells;
31             range.HorizontalAlignment = base.Alignment;
32             base.DrawGridLine();
33         }

Excel导出报表的流程一般为:启动Excel应用程序,初始化工作簿,初始化sheet,写入报表,保存文件,关闭工作簿,退出Excel。

因此封装工作流程类:

xlsApp
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using Excel = Microsoft.Office.Interop.Excel;
 6 using System.Diagnostics;
 7 namespace NtExcel
 8 {
 9    public class xlsApp
10     {
11         public  Excel._Application xlApp;
12         public  Excel.Worksheet sheet;
13         Excel.Workbook book;
14         public void InitReport(string _Sheetname,int _SheetIndex=1)
15         {
16             xlApp = new Excel.ApplicationClass();
17             if (xlApp == null)
18             {
19                 throw new ArgumentException("Excel无法启动,可能是您未安装Excel软件.");
20             }
21             object missing = System.Reflection.Missing.Value;
22             xlApp.Workbooks.Add(missing);
23 
24             book = xlApp.Workbooks[1];
25             sheet = (Excel.Worksheet)book.Sheets[_SheetIndex];
26             sheet.Name = _Sheetname;
27         }
28         public void KillExcelProcess()
29         {
30             Process[] myProcesses;
31             myProcesses = Process.GetProcessesByName("Excel");
32 
33             foreach (Process myProcess in myProcesses)
34             {
35                 myProcess.Kill();
36             }
37         }
38         private void ReleaseObject(object obj)
39         {
40             try
41             {
42                 System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
43             }
44             catch { }
45             finally { obj = null; }
46         }
47        public void SaveReport(string filename)
48         {
49             xlApp.DisplayAlerts = false;
50             book.SaveCopyAs(filename);
51             xlApp.Workbooks.Close();
52             xlApp.Quit();
53             sheet = null;
54             this.ReleaseObject(book);
55             this.ReleaseObject(xlApp);
56         }
57     }
58 }

位运算的应用:
借鉴Window窗体样式设置的思想用‘|’按位并操作实现样式的叠加。因为区域的边框有六种样式,用户可以设置不同的样式组合。每一种特性用二进制的0和1表示,每位表示一种特性。如A=0001、B=0010、C=0100、D=1000表示四种特性,通用'|'运算获得style,style1=A|B|C=0111,style2=B|C=0110。用'&'获的是否包含此特性,style&A=0001,style2&A=0000。

        public const uint Grid_InsideHorizontal = 0x0001;
        public const uint Grid_InsideVertical = 0x0002;
        public const uint Grid_EdgeTop = 0x0004;
        public const uint Grid_EdgeBottom = 0x0008;
        public const uint Grid_EdgeLeft = 0x0010;
        public const uint Grid_EdgeRight = 0x0020;

类的调用实例如下:

调用的示例
 1   private void button2_Click(object sender, EventArgs e)
 2         {
 3             OracleHelper.connectionString = "Data Source =demo; User Id =peouser; Password =123; Integrated Security = no";
 4             csRegions reg = new csRegions();
 5             reg.Fetch();
 6             object[,] objs = new object[csRegions.list.Count, 1];
 7             int i=0;
 8             foreach (string str in csRegions.list)
 9             {
10                 objs[i, 0] = str;
11                 i++;
12             }
13             string VirFileName = "D:\\" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xls";
14 
15             xlsApp excel = new xlsApp();
16             excel.InitReport("很好啊");
17 
18             xlsRegion.xlApp = excel.xlApp;
19             xlsRegion.sheet = excel.sheet;
20 
21             xlsCell cel1 = new xlsCell(1, 1);
22             xlsTitle xls_Title = new xlsTitle(cel1, 10);
23             xls_Title.Title = "我是中国人!";
24             xls_Title.SetStyle();
25             xls_Title.FillData();
26             
27             cel1.MoveTo(2, 1);
28             int rowsData = objs.GetLength(0);
29             xlsRegion xls_Region = new xlsRegion(cel1, rowsData, 1);
30             xls_Region.Objdata = objs;
31             xls_Region.FillData();
32             xls_Region.SetStyle();
33 
34             cel1.MoveTo(2, 2);
35             xlsColumnHeader xls_Column = new xlsColumnHeader(cel1,9);
36             List<string> listheader = new List<string>();
37             listheader.Add("姓名");
38             listheader.Add("工种");
39             xls_Column.Headers = listheader;
40             xls_Column.FillData();
41             xls_Column.SetStyle();
42 
43             excel.SaveReport(VirFileName);
44             GC.Collect();
45 
46             excel.KillExcelProcess();
47         }

posted @ 2012-12-29 09:50  太一吾鱼水  阅读(510)  评论(8编辑  收藏  举报