在C#中利用Excel做高級報表

 

C#中利用Excel做高級報表

   http://www.souzz.net 2005-10-14 文章出處:轉載uncj

 

 

    

Visual Studio.Net 20012月問世以來,受到越來越多人的喜愛,C#做爲主力軍,集VBDelphi的簡單和VC的簡煉與強大於一體,更是讓許多人愛不釋手,紛紛倒向它的懷抱。通常的軟件都要用到數據庫,數據庫中必然要用到報表,在Visual Studio.Net中自帶了一個水晶報表,雖然功能十分強大,但市面上相關資料非常缺乏,網上全面介紹其使用的文章也屈指可數。Excel是微軟公司辦公自動化套件中的一個軟件,主要是用來處理電子表格。Excel以其功能強大,界面友好等受到了許多用戶的歡迎,幾乎每一臺機器都安裝了它,因此,我們可以將數據導入Excel進行排版。 

由於Excel的格式是封閉的,無法直接創建一個Excel文件然後來排版,只有藉助Com組件來完成,同樣,介紹用C#操作Excel的文章也就那麼幾篇,基本上都是告訴你如何新建一個Excel文件,然後,將數據寫入某單元格,最多再零星告訴你如何合併單元格,真正使用起來根本無法用C#做出漂亮報表。本文巧妙利用Excel的宏來自動排版,大大減少了工作量,而且可以隨時修改模板而無須修改程序,非常實用。

本人使用的是Office 2000,操作系統爲windows 2000 professinal,爲使問題簡單化,這裏不介紹數據庫的知識,我一個二維數組來代表一個數據庫中的表,我們的目的是將該數組放到Excel中,並排版成需要的格式,數組如下:

車牌號         附加費證號 車架號 
KA3676 危險品 貨車 鐵風SZG9220YY  1110708900 022836 
KA4109 危險品 貨車 解放CA4110P1K2  223132 010898 
KA0001A 危險品 貨車 南明LSY9190WS  1110205458 0474636 
KA0493 上普貨 貨車 解放LSY9190WS  1110255971 0094327 
KA1045 普貨 貨車 解放LSY9171WCD  1110391226 0516003 
KA1313 普貨 貨車 解放9190WCD  1110315027 0538701 
KA1322 普貨 貨車 解放LSY9190WS  24323332 0538716 
KA1575 普貨 貨車 解放LSY9181WCD  1110314149 0113018 
KA1925 普貨 貨車 解放LSY9220WCD  1110390626 00268729 
KA2258 普貨 貨車 解放LSY9220WSP  1110481542 00320 

爲了在C#中使用Excel,我們要先做一點準備工作,通過查找(前提是你安裝Visual Studio.NetExcel 2000),在你的計算機中找到TlbImpExcel9.olb,將他們複製到一個文件夾中,在DOS窗口中執行 TlbImp Excel9.olb,這時會產生以下三個文件:Excel.dllOffice.dllVBIDE.dll

我們來完成兩項任務,一是按網上文章介紹的方法,增加將數據寫入一個Excel文件,也就是做一個簡單報表,二是用Excel創建一個文件,然後以此文件爲模板生成高級報表。

打開Visual Studio.Net,新建一個C#windows應用程序,取名爲MyExcel。根據個人愛好,對窗口做一些美化工作,然後放兩個按鈕:btnNormalbtnAdvanceCaption分別爲普通報表高級報表

打開Visual Studio.Net,新建一個C#windows應用程序,取名爲MyExcel。根據個人愛好,對窗口做一些美化工作,然後放兩個按鈕:btnNormalbtnAdvanceCaption分別爲普通報表高級報表

打開按鈕,再點確定按鈕。 

切換到代碼窗口中,在文件頭添加下面兩個引用: 

using System.IO;
using System.Reflection;

再添加一個二維數組來表示數據表:

private string [,] myData= 

         {

              {"
車牌號",""," "," "," ","附加費證號","車架號"},

              {"
KA3676","危險品","貨車","鐵風SZG9220YY","","1110708900","022836"},

              {"
KA4109","危險品","貨車","解放CA4110P1K2","","223132","010898"},

              {"
KA0001A","危險品","貨車","南明LSY9190WS","","1110205458","0474636"},

              {"
KA0493","上普貨","貨車","解放LSY9190WS","","1110255971","0094327"},

              {"
KA1045","普貨","貨車","解放LSY9171WCD","","1110391226","0516003"},

              {"
KA1313","普貨","貨車","解放9190WCD","","1110315027","0538701"},

              {"
KA1322","普貨","貨車","解放LSY9190WS","","24323332","0538716"},

              {"
KA1575","普貨","貨車","解放LSY9181WCD","","1110314149","0113018"},

              {"
KA1925","普貨","貨車","解放LSY9220WCD","","1110390626","00268729"},

              {"
KA2258","普貨","貨車","解放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.Cells[1,4]="
普通報表";

              //
逐行寫入數據,

              for(int i=0;i<11;i++)
              {
                   for(int j=0;j<7;j++)
                   {
                       //
以單引號開頭,表示該單元格爲純文本
                       myExcel.Cells[2+i,1+j]="’"+myData[i,j];
                   }
              }
         }

說明一下,Cells[2,1]指第2行第1個單元格,是以1爲基準的,而在C#中的數組是以0爲基準的,另外,我們還發現,對於編號之的數據,實際是文本,而Excel將它認成了數字,由於太長,自動換成了科學計數,這不是我們要求的,在Excel中,如果某單元格以單引號“’”開頭,表示該單元格爲純文本,因此,我們在每個單元格前面加單引號。

運行結果如下:

可以看出,該報表非常簡陋,標題行沒有合併局,字體大小也不合適,連表格線都沒有。當然,我們可以寫代碼來設置單元格字體、大小等等工作,這技巧網上很多,但如果真要用C#來完成,是一件非常難的事情,還有個辦法就是將想要的操作錄製成宏,研究一下宏代碼,但宏是用VBA寫的,要轉換成果C#可不是件容易的事情。

第一種辦法不是本文的重點,就到此爲止

下面進行高級報表設計,該方法的原理爲:首先打開Excel,按照要求排好版,保存爲一個文件做爲模板,然後在C#中將該文件複製爲一個新文件,在指定位置填入數據就可以了,爲了添加表格線,我們錄製了一個宏,在C#中執行該宏即可。

參考模板如下:

當然,你還可以排得更漂亮,因爲是單純的Excel操作,不需要特殊說明。如果記錄很多,往往一頁無法打印完成,我們要求在每一頁都顯示報表標題和小標題,也就是上圖中的第12行,這裏有一個技巧:選擇Excel的菜單文件”→“頁面設置,選擇工作表,在頂端標題行後的框中輸入“$1:$2”,也就是12行,當然,你也點右邊的紅箭頭,然後用鼠標選擇。當你的記錄超過一頁時,會自動在下一頁加入標題,非常方便。

表格中目前還沒有表格線,因爲我們不知道到底有多少數據,因此,也無法知道爲多少單元格設置邊框,我們藉助宏來完成。 

按下面步驟錄製一個宏:

1
、隨便選擇幾個單元格;
2
、選擇菜單工具”→“”→“錄製新宏,輸入宏的名稱,就用默認的1”吧,點確定;
3
、選擇菜單格式”→“單元格,在對話框中選擇邊框,將內邊框和外邊框均選中,按確定;
4
、此時,剛纔選擇的單元格就有了邊框,再點工具欄中的停止錄製宏按鈕 來結束宏錄製。

剛纔的操作目的是錄製宏而不是加邊框,因此,我們按“Ctrl+Z”來撤消剛纔的操作,通過按Alt+F8來調出宏,選擇1”,選擇編輯,看到的代碼應該如下: 

Sub 1()
’ 
1 Macro
’ xx 
記錄的宏 2003-5-1

    Selection.Borders(xlDiagonalDown).LineStyle = xlNone

    Selection.Borders(xlDiagonalUp).LineStyle = xlNone

    With Selection.Borders(xlEdgeLeft)

        .LineStyle = xlContinuous

        .Weight = xlThin

        .ColorIndex = xlAutomatic

    End With

    With Selection.Borders(xlEdgeTop)

        .LineStyle = xlContinuous

        .Weight = xlThin

        .ColorIndex = xlAutomatic

    End With

    With Selection.Borders(xlEdgeBottom)

        .LineStyle = xlContinuous

        .Weight = xlThin

        .ColorIndex = xlAutomatic

    End With

    With Selection.Borders(xlEdgeRight)

        .LineStyle = xlContinuous

        .Weight = xlThin

        .ColorIndex = xlAutomatic

    End With

    With Selection.Borders(xlInsideVertical)

        .LineStyle = xlContinuous

        .Weight = xlThin

        .ColorIndex = xlAutomatic

    End With

    With Selection.Borders(xlInsideHorizontal)

        .LineStyle = xlContinuous

        .Weight = xlThin

        .ColorIndex = xlAutomatic

    End With

End Sub

圖中表的數據都是供排版參考用的,結束前將實際內容刪除掉,即只留下排好版的格式,包括標題、列標題等,將實際內容去掉。將文件保存到一個地方,如D:/Normal.xls,當然,實際開發時,可以放到執行文件所在目錄下,爲了防止用戶隨便修改,可以將文件名改爲normal.rpt 

有了上面的準備,我們就可以在C#中使用了,添加高級報表按鈕的響應代碼。下面是全部代碼清單。

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

 

using System.IO;

using System.Reflection;

 

namespace MyExcel

{

     /// <summary>

     /// Form1 
的摘要說明。

     /// </summary>

     public 
class Form1 : System.Windows.Forms.Form

     {

         private System.Windows.Forms.Button btnNormal;

         private System.Windows.Forms.Button btnAdvace;

         /// <summary>

         /// 
必需的設計器變量。

         /// </summary>

         private System.ComponentModel.Container components = null;

 

         public Form1()

         {

              //

              // Windows 
窗體設計器支持所必需的

              //

              InitializeComponent();

 

              //

              // TODO: 
 InitializeComponent 調用後添加任何構造函數代碼

              //

         }

 

         /// <summary>

         /// 
清理所有正在使用的資源。

         /// </summary>

         protected override void Dispose( bool disposing )
         {

              if( disposing )

              {

                   if (components != null) 

                   {

                       components.Dispose();

                   }

              }

              base.Dispose( disposing );

         }

 

         #region Windows Form Designer generated code

         /// <summary>

         /// 
設計器支持所需的方法 - 不要使用代碼編輯器修改

         /// 
方法的內容。

         /// </summary>

         private 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.btnNormal.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(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.FormStartPosition.CenterScreen;

              this.Text = "Form1";

              this.ResumeLayout(false);

 

         }

         #endregion

 

         /// <summary>

         /// 
應用程序的主入口點。

         /// </summary>

         [STAThread]

         static void Main() 

         {

              Application.Run(new Form1());

         }

 

         private string [,] myData= 

         {

              {"
車牌號",""," "," "," ","附加費證號","車架號"},

              {"
KA3676","危險品","貨車","鐵風SZG9220YY","","1110708900","022836"},

              {"
KA4109","危險品","貨車","解放CA4110P1K2","","223132","010898"},

              {"
KA0001A","危險品","貨車","南明LSY9190WS","","1110205458","0474636"},

              {"
KA0493","上普貨","貨車","解放LSY9190WS","","1110255971","0094327"},

              {"
KA1045","普貨","貨車","解放LSY9171WCD","","1110391226","0516003"},

              {"
KA1313","普貨","貨車","解放9190WCD","","1110315027","0538701"},

              {"
KA1322","普貨","貨車","解放LSY9190WS","","24323332","0538716"},

              {"
KA1575","普貨","貨車","解放LSY9181WCD","","1110314149","0113018"},

              {"
KA1925","普貨","貨車","解放LSY9220WCD","","1110390626","00268729"},

              {"
KA2258","普貨","貨車","解放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.Cells[1,4]="
普通報表";

              //
逐行寫入數據,

              for(int i=0;i<11;i++)
              {
                   for(int j=0;j<7;j++)
                   {
                       //
以單引號開頭,表示該單元格爲純文本
                       myExcel.Cells[2+i,1+j]="’"+myData[i,j];
                   }
              }
         }

         //
高級報表,根據模板生成的報表

         private 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;

              }

              else

              {

                   filename=mySave.FileName;

                   //
將模板文件copy到新位置,建議實際開發時用相對路徑,如
                   //Application.StartupPath.Trim()+"//report//normal.xls"

                   

                   string filenameold=mySave.FileName;

                   FileInfo mode=new FileInfo("d://normal.xls");

                   try

                   {

                       mode.CopyTo(filename,true);

                   }

                   catch(Exception ee)

                   {

                       MessageBox.Show(ee.Message);

                       return;

                   }

 

              }

 

              //
打開復制後的文件

              object missing=Missing.Value;

              Excel.Application myExcel=new Excel.Application ( );

              //
打開新文件

              myExcel.Application.Workbooks.Open(filename,missing,missing,missing,missing,
                missing,missing,missing,missing,missing,missing, missing,missing); 

              //
Excel顯示出來

              myExcel.Visible=true;
              //
逐行寫入數據,數組中第一行我列標題,忽略

              for(int i=1;i<11;i++)
              {
                   for(int j=0;j<7;j++)
                   {
                       //
以單引號開頭,表示該單元格爲純文本

                       myExcel.Cells[4+i,1+j]="’"+myData[i,j];

                   }

              }

              //
將列標題和實際內容選中

              Excel.Workbook myBook=myExcel.Workbooks[1];

              Excel.Worksheet mySheet=(Excel.Worksheet)myBook.Worksheets[1];

              Excel.Range r=mySheet.get_Range(mySheet.Cells[3,1],mySheet.Cells[14,7]);

              r.Select();

              //=====
通過執行宏來格表格加邊框=======//

              try

              {

                   myExcel.Run("
1",missing,missing, 

 

                       missing,missing,missing,missing,missing,missing,missing, 

 

                       missing,missing,missing,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.Cells[3,1],mySheet.Cells[14,7]);

具體開發時,我們可以根據數據庫中的實際數據來計算範圍,我們的列標題是從.Cells[3,1]開始的,在程序中定死了,爲靈活使用,我們完全可以在模板的Cells[1,1]或者其他單元格填入一些基本信息,如實際數據起始位置等等,操作時,從該單元格讀入數據,然後將該單元格內容替換成需要的內容。還有個問題,我們往單元格中寫內容時假設某列應該放什麼內容,爲靈活起見,我們在得到了列標題起始位置後,讀入該單元格內容(即該列應該是什麼字段),再從數據庫中找到相應的字段來填充該列,可以保證所填內容與設計的報表對應起來,還可以忽略數據庫中無用的字段,也就是說同一個數據庫表可以有許多種報表,只要有相應的模板就可以了,讀入某單元格內容的代碼如下:

     Excel.Range r;
     r=mySheet.get_Range(mySheet.Cells[2,1],mySheet.Cells[2,1]);  //
取得值存放的區域
     string strValue=r.Value.ToString();

一次只能讀一個單元格,否則得不到相應的數據,即=mySheet.get_Range(mySheet.Cells[2,1],mySheet.Cells[2,1])中兩個參數都必須是同一個單元格,本例中爲mySheet.Cells[2,1]

有了上面的知識,再做報表就簡單多了,本軟件運行結果如下:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章