1、在 C#中利用 Excel 做高级报表浙江省丽水市汽车运输集团有限公司信息中心 苟安廷 http:/Visual Studio.Net 自 2001 年2 月问世以来,受到越来越多人的喜爱,C#做为主力军,集 VB、 Delphi的简单和 VC的简炼与强大于一体,更是让许多人 爱不释手,纷纷倒向它的怀抱。通常的软件都要用到数据库,数据库中必然要用到报表,在 Visual Studio.Net 中自带了一个水晶报表,虽然功能十分强大,但市面上相关资料非常缺乏 ,网上全面介绍其使用的文章也屈指可数。Excel 是微软公司办公自动化套件中 的一个软件,主要是用来处理电子表格。Excel 以其功能强大
2、,界面友好等受到了许多用户 的欢迎,几乎每一台机器都安装了它,因此,我们可以将数据导入 Excel 进行排版。由于 Excel 的格式是封闭的,无法直接创建 一个 Excel 文件然后来 排版,只有借助Com 组件来完成 ,同样,介绍用 C#操作 Excel 的文章也就 那么几篇,基本上都是告 诉你如何新建一个 Excel 文件,然后,将数据写入某单元格,最多再零星告 诉你如何合并单元格,真正使用起来根本无法用 C#做出漂亮报表。本文巧妙利用 Excel 的宏来自动排版,大大减少了工作量,而且可以随时修改模板而无须修改程序,非常实用。本人使用的是Office 2000,操作系统为 window
3、s 2000 professinal,为使问题简单化,这里不介绍数据库的知识,我一个二维数组来代表一个数据库中的表 ,我们的目的是将该数组放到Excel 中,并排版成需要 的格式,数组如下:车牌号 类 型 品 牌 型 号 颜 色 附加费证号 车架号浙 KA3676 危险品 货车 铁风 SZG9220YY 白 1110708900 022836浙 KA4109 危险品 货车 解放 CA4110P1K2 白 223132 010898浙 KA0001A 危险品 货车 南明 LSY9190WS 白 1110205458 0474636浙 KA0493 上普货 货车 解放 LSY9190WS 白 11
4、10255971 0094327浙 KA1045 普货 货车 解放 LSY9171WCD 蓝 1110391226 0516003浙 KA1313 普货 货车 解放 9190WCD 蓝 1110315027 0538701浙 KA1322 普货 货车 解放 LSY9190WS 蓝 24323332 0538716浙 KA1575 普货 货车 解放 LSY9181WCD 蓝 1110314149 0113018浙 KA1925 普货 货车 解放 LSY9220WCD 蓝 1110390626 00268729浙 KA2258 普货 货车 解放 LSY9220WSP 蓝 1110481542 00
5、320为了在 C#中使用 Excel,我们要先做一点准备工作,通过查找(前提是你安装Visual Studio.Net 和 Excel 2000) ,在你的计算机 中找到 TlbImp 和 Excel9.olb,将他们复制到一个文件夹中,在 DOS 窗口中执行 TlbImp Excel9.olb,这时会产生以下三个文件:Excel.dll、Office.dll 和 VBIDE.dll。我们来完成两项任务,一是按网上文章介绍的方法,增加将数据写入一个 Excel 文件,也就是做一个简单报表,二是用 Excel 创建一个文件,然后以此文件 为模板生成高级报表。打开 Visual Studio.Ne
6、t,新建一个 C#的 windows 应用程序,取名为 MyExcel。根据个人爱好,对窗口做一些美化工作,然后放两个按钮:btnNor mal 和 btnAdvance,Captio n 分别为“普通报表”和“高级报表” 。从菜单中选择“项目”“添加应用” ,在弹出的对话框中选 com页,再点浏览按钮,选择刚才生成的三个文件,如下:点“打开”按钮,再点“确定”按钮。切换到代码窗口中,在文件头添加下面两个引用:using System.IO;using System.Reflection;再添加一个二维数组来表示数据表:private string , myData= “车牌号“,“类 型“,
7、“品 牌“,“型 号“,“颜 色“,“附加费证号“,“车架号“,“浙KA3676“,“危险品“,“货车“,“铁风SZG9220YY“,“白“,“1110708900“,“022836“,“浙KA4109“,“危险品“,“货车“,“解放CA4110P1K2“,“白“,“223132“,“010898“,“浙KA0001A“,“危险品“,“货车“,“南明LSY9190WS“,“白“,“1110205458“,“0474636“,“浙KA0493“,“上普货“,“货车“,“解放LSY9190WS“,“白“,“1110255971“,“0094327“,“浙KA1045“,“普货“,“货车“,“解放L
8、SY9171WCD“,“蓝“,“1110391226“,“0516003“,“浙KA1313“,“普货“,“货车“,“解放9190WCD“,“蓝“,“1110315027“,“0538701“,“浙KA1322“,“普货“,“货车“,“解放LSY9190WS“,“蓝“,“24323332“,“0538716“,“浙KA1575“,“普货“,“货车“,“解放LSY9181WCD“,“蓝“,“1110314149“,“0113018“,“浙KA1925“,“普货“,“货车“,“解放LSY9220WCD“,“蓝“,“1110390626“,“00268729“,“浙KA2258“,“普货“,“货车“
9、,“解放LSY9220WSP“,“蓝“,“111048152“,“00320“;切换回设计窗口,双击“普通报表”按钮,设计普通报表,代码如下:private void btnNormal_Click(object sender, System.EventArgs e)/创建一个Excel文件Excel.Application myExcel = new Excel.Application ( ) ;myExcel.Application.Workbooks.Add ( true ) ;/让Excel文件可见myExcel.Visible=true;/第一行为报表名称myExcel.Cells1
10、,4=“普通报表“;/逐行写入数据,for(int i=0;i/ Form1 的摘要说明。/ public class Form1 : System.Windows.Forms.Formprivate System.Windows.Forms.Button btnNormal;private System.Windows.Forms.Button btnAdvace;/ / 必需的设计器变量。/ private System.ComponentModel.Container components = null;public Form1()/ Windows 窗体设计器支持所必需的/Initia
11、lizeComponent();/ TODO: 在 InitializeComponent 调用后添加任何构造函数代码/ / 清理所有正在使用的资源。/ protected override void Dispose( bool disposing )if( disposing )if (components != null) components.Dispose();base.Dispose( disposing );#region Windows Form Designer generated code/ / 设计器支持所需的方法 - 不要使用代码编辑器修改/ 此方法的内容。/ priva
12、te void InitializeComponent()this.btnNormal = new System.Windows.Forms.Button();this.btnAdvace = new System.Windows.Forms.Button();this.SuspendLayout();/ / btnNormal/ this.btnNormal.Location = new System.Drawing.Point(49, 55);this.btnNormal.Name = “btnNormal“;this.btnNormal.TabIndex = 0;this.btnNorm
13、al.Text = “普通报表“;this.btnNormal.Click += new System.EventHandler(this.btnNormal_Click);/ / btnAdvace/ this.btnAdvace.Location = new System.Drawing.Point(169, 55);this.btnAdvace.Name = “btnAdvace“;this.btnAdvace.TabIndex = 1;this.btnAdvace.Text = “高级报表“;this.btnAdvace.Click += new System.EventHandler
14、(this.btnAdvace_Click);/ / Form1/ this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);this.ClientSize = new System.Drawing.Size(292, 133);this.Controls.AddRange(new System.Windows.Forms.Control this.btnAdvace,this.btnNormal);this.Name = “Form1“;this.StartPosition = System.Windows.Forms.FormStart
15、Position.CenterScreen;this.Text = “Form1“;this.ResumeLayout(false);#endregion/ / 应用程序的主入口点。/ STAThreadstatic void Main() Application.Run(new Form1();private string , myData= “车牌号“,“类 型“,“品 牌“,“型 号“,“颜 色“,“附加费证号“,“车架号“,“浙KA3676“,“危险品“,“货车“,“铁风SZG9220YY“,“白“,“1110708900“,“022836“,“浙KA4109“,“危险品“,“货车“,
16、“解放CA4110P1K2“,“白“,“223132“,“010898“,“浙KA0001A“,“危险品“,“货车“,“南明LSY9190WS“,“白“,“1110205458“,“0474636“,“浙KA0493“,“上普货“,“货车“,“解放LSY9190WS“,“白“,“1110255971“,“0094327“,“浙KA1045“,“普货“,“货车“,“解放LSY9171WCD“,“蓝“,“1110391226“,“0516003“,“浙KA1313“,“普货“,“货车“,“解放9190WCD“,“蓝“,“1110315027“,“0538701“,“浙KA1322“,“普货“,“货
17、车“,“解放LSY9190WS“,“蓝“,“24323332“,“0538716“,“浙KA1575“,“普货“,“货车“,“解放LSY9181WCD“,“蓝“,“1110314149“,“0113018“,“浙KA1925“,“普货“,“货车“,“解放LSY9220WCD“,“蓝“,“1110390626“,“00268729“,“浙KA2258“,“普货“,“货车“,“解放LSY9220WSP“,“蓝“,“111048152“,“00320“;/普通报表,即单纯的文件导出功能private void btnNormal_Click(object sender, System.EventAr
18、gs e)/创建一个Excel文件Excel.Application myExcel = new Excel.Application ( ) ;myExcel.Application.Workbooks.Add ( true ) ;/让Excel文件可见myExcel.Visible=true;/第一行为报表名称myExcel.Cells1,4=“普通报表“;/逐行写入数据,for(int i=0;i11;i+)for(int j=0;j7;j+)/以单引号开头,表示该单元格为纯文本myExcel.Cells2+i,1+j=“+myDatai,j;/高级报表,根据模板生成的报表private
19、void btnAdvace_Click(object sender, System.EventArgs e)string filename=“;/将模板文件复制到一个新文件中SaveFileDialog mySave=new SaveFileDialog();mySave.Filter=“Excel文件(*.XLS)|*.xls|所有文件(*.*)|*.*“;if(mySave.ShowDialog()!=DialogResult.OK)return;elsefilename=mySave.FileName;/将模板文件copy到新位置,建议实际开发时用相对路径,如Application.S
20、tartupPath.Trim()+“reportnormal.xls“string filenameold=mySave.FileName;FileInfo mode=new FileInfo(“d:normal.xls“);trymode.CopyTo(filename,true);catch(Exception ee)MessageBox.Show(ee.Message);return;/打开复制后的文件object missing=Missing.Value;Excel.Application myExcel=new Excel.Application ( );/打开新文件myExce
21、l.Application.Workbooks.Open(filename,missing,missing,missing,missing,missing,missing,missing,missing,missing,missing,missing,missing); /将Excel显示出来myExcel.Visible=true;/逐行写入数据,数组中第一行我列标题,忽略for(int i=1;i11;i+)for(int j=0;j7;j+)/以单引号开头,表示该单元格为纯文本myExcel.Cells4+i,1+j=“+myDatai,j;/将列标题和实际内容选中Excel.Workb
22、ook myBook=myExcel.Workbooks1;Excel.Worksheet mySheet=(Excel.Worksheet)myBook.Worksheets1;Excel.Range r=mySheet.get_Range(mySheet.Cells3,1,mySheet.Cells14,7);r.Select();/=通过执行宏来格表格加边框=/trymyExcel.Run(“宏1“,missing,missing, missing,missing,missing,missing,missing,missing,missing, missing,missing,missi
23、ng,missing,missing,missing,missing, missing,missing,missing,missing,missing,missing,missing, missing,missing,missing,missing,missing,missing,missing); catch/保存修改myBook.Save();/end of form在上述代码中,我们指定了选定范围:Excel.Range r=mySheet.get_Range(mySheet.Cells3,1,mySheet.Cells14,7);具体开发时,我们可以根据数据库中的实际数据来计算范围,我
24、们的列标题是从.Cells3,1开始的,在程序中定死了,为灵活使用,我们完全可以 在模板的 Cells1,1或者其他单元格填入一些基本信息,如实际数据起始位置等等,操作时,从该单元格读 入数据,然后将该单元格内容替换成需要的内容。还有个问题,我们往单元格 中写内容时假设某列应该放什么内容,为灵活起见,我们在得到了列标题起始位置后,读入该单元格 内容(即该列应该是什么字段) ,再从数据库中找到相应的字段来填充该列 ,可以保证所填内容与设计的报表对应起来,还可以忽略数据库中无用的字段,也就是说同一 个数据库表可以有许多种报表,只要有相应的模板就可以了,读入某单元格内容的代码如 下:Excel.Range r;r=mySheet.get_Range(mySheet.Cells2,1,mySheet.Cells2,1); /取得值存放的区域string strValue=r.Value.ToString();一次只能读一个单元格,否则得不到相应的数据,即=mySheet.get_Range(mySheet.Cells2,1,mySheet.Cells2,1)中两个参数都 必须是同一个单元格,本例中为 mySheet.Cells2,1。有了上面的知识,再做报表就简单多了,本软件运行结果如下: