c#操作Excel模板,替換命名單元格或關鍵字形成報表


c#操作Excel模板,替換命名單元格或關鍵字形成報表

http://blog.sina.com.cn/s/blog_45eaa01a0102vqma.html
一 建立Excel 模板文件 template.xls

c#操作Excel模板,替換命名單元格或關鍵字形成報表


1.1 插入命名單元格的方法:

左上角名稱框,顯示當前單元格的行列號C2,加入命名后會顯示其命名name

方法一:

(1) 點擊 單元格“姓名”之后的單元格
(2) 菜單 插入--名稱--定義
(3) 在框中輸入 name

   確保底部的引用位置為 =Users!$C$2
   按“添加”、“確定”按鈕 即可

c#操作Excel模板,替換命名單元格或關鍵字形成報表

方法二:
(1) 點擊 單元格“姓名”之后的單元格
(2) 在左上角名稱框中,輸入名稱即可  

1.2 制作模板如下:
(1) 在1行1列,寫入序號,在2行1列,插入名稱  order_num
(2) 在1行2列,寫入“報告日期”,在1行3列,插入名稱  _報告日期
(3) 在2行2列,寫入"姓名",在2行3列,插入名稱  name
(4) 在3行2列,寫入"年齡",在3行3列,插入名稱  age
(5) 在3行2列,寫入"結論",在3行3列,插入名稱  _結論

c#操作Excel模板,替換命名單元格或關鍵字形成報表

二 建立一個,WindowForm格式的解決方案WindowsFormsApplication10

 

三 添加對Excel的引用
1 右擊工程的“應用”文件夾--“添加引用”--在“COM”選項頁,
  選擇“Microsoft Excel 11.0 Object Library”,添加到本工程中,針對office 2003
  並自動引入“Microsoft Office 11.0 Object Library”
c#操作Excel模板,替換命名單元格或關鍵字形成報表

 

2 在實現的文件中,加入引用語句:using Excel=Microsoft.Office.Interop.Excel;
  按需要,是否加入引用語句:using Microsoft.Office.Core;


3 注意:如果工程中,曾經加入過Excel,office,VBIDE相同的引用,則再加入后,
需要從該引用的“屬性”中,將“潛入互操作類型”從True 改變為 False,否則無法編譯

c#操作Excel模板,替換命名單元格或關鍵字形成報表

 

 

四 建立一個操作EXCEL的類ExcelTemplate,並在實際工程中,創建類對象即可。
   特別注意:為了程序自動處理方便起見,命名單元格的規則如下:
   1.1 開頭處的命名單元格,以1個下划線開始,比如,_報告日期
   1.2 中間多行組循環的命名單元格,不加下划線,且與數據集的字段名一致為好
   1.3 結尾處的命名單元格,以2個下划線開頭,比如,__合計

 

五 結果如下:

c#操作Excel模板,替換命名單元格或關鍵字形成報表

六 完整代碼如下:

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
//1 右擊工程的“應用”文件夾--“添加引用”--在“COM”選項頁,
//  選擇“Microsoft Excel 11.0 Object Library”,添加到本工程中,針對office 2003
//  並自動引入“Microsoft Office 11.0 Object Library”
//2 在實現的文件中,加入引用語句:using Excel=Microsoft.Office.Interop.Excel;
//  按需要,是否加入引用語句:using Microsoft.Office.Core;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.Office.Core;
namespace WindowsFormsApplication10
{
//一 主界面文件
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {//這里演示打開模板文件,替換后保存成實際數據的文件
            //1 定位Excel模板文件template.xls
            string str;
            str = Application.StartupPath;//工作路徑
            //       str = Application.ExecutablePath;
            //       str = Environment.CurrentDirectory;
            //       str = System.IO.Directory.GetCurrentDirectory();
            //       str=AppDomain.CurrentDomain.BaseDirectory;
            //d:\WindowsFormsApplication10\WindowsFormsApplication10\bin\Debug\
            //d:\WindowsFormsApplication10\WindowsFormsApplication10\template.xls
            int pos = -1;
            pos = str.IndexOf("\\bin\\Debug");
            string strPath = str;
            if (pos > 0) strPath = str.Substring(0, pos);
            else
            {
                pos = str.IndexOf("\\bin\\Release");
                if (pos > 0) strPath = str.Substring(0, pos);
            }
            str = strPath + "\\template.xls";
           
            //2 生成模板類的對象 ,並打開模板文件
            ExcelTemplate  em = new ExcelTemplate ();
            em.Open(str);// ("c:\\d.xls");//"template.xls"

            //3 這里簡單生成樣例數據表,工作中要以實際的數據集為准
            DataTable dt = new DataTable();
            dt.Columns.Add("name", typeof(string));
            dt.Columns.Add("age", typeof(int));

            DataRow dr = dt.NewRow();
            dr["name"] = "張三"; dr["age"] = 20;
            dt.Rows.Add(dr);

            dr = dt.NewRow();
            dr["name"] = "李四"; dr["age"] = 25;
            dt.Rows.Add(dr);

            //4調用模板替換函數,生成實際的數據
            em.SetNameCellValue(dt);

            //5 按當天日期 存盤
            string execlName = strPath + "\" + DateTime.Now.ToString("yyyyMMdd-hhmmss") + ".xls";
            em.SaveAs(execlName);

            //6 退出
            em.Close();
            MessageBox.Show(execlName + "     生成成功!");
           

        }
    }

//二 打開Excel模板的類,替換命名單元格的數據,生成實際的數據結果文件
    public class ExcelTemplate
    {
        public string mFilename;
        public Excel.Application app;
        public Excel.Workbooks wbs;
        public Excel.Workbook wb;
        public Excel.Worksheets wss;
        public Excel.Worksheet ws;
        public ExcelTemplate()
        {
            //
            // TODO: 在此處添加構造函數邏輯
            //
        }
        public void Create()//創建一個Excel對象
        {
            app = new Excel.Application();
            wbs = app.Workbooks;
            wb = wbs.Add(true);
        }
        public void Open(string FileName)//打開一個Excel文件
        {
            app = new Excel.Application();
            wbs = app.Workbooks;
            wb = wbs.Add(FileName);
            //wb = wbs.Open(FileName,  0, true, 5,"", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true,Type.Missing,Type.Missing);
            //wb = wbs.Open(FileName,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Excel.XlPlatform.xlWindows,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing);
            mFilename = FileName;
        }
        public Excel.Worksheet SetNameValue(string SheetName)//獲取一個工作表
        {
            Excel.Worksheet s = (Excel.Worksheet)wb.Worksheets[SheetName];
            return s;
        }

        public void SetNameCellValue(DataTable dt)//Excel.Worksheet ws, ws:要設值的工作表   ,數據源表  dt
        {
            Excel.Worksheet ws = (Excel.Worksheet)app.ActiveSheet;
            // ws.Range[ws.Cells[1, 255], ws.Cells[1, 255]].Copy();

            //(一) 這里設置表頭的項目,比如報表日期
            //特別注意:為了容易起見,命名單元格的規則如下
            //1.1 開頭處的命名單元格,以1個下划線開始,比如,_報告日期
            //1.2 中間循環命名單元格,就是正常的,與數據集的字段名一致為好
            //1.3 結尾處的命名單元格,以2個下划線開頭,比如,__合計
            try
            {//為了程序自動處理方便起見
                app.Goto("_報告日期");
                app.ActiveCell.FormulaR1C1 = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
                //str = app.ActiveCell.Value.ToString();//ws.Evaluate[titleName]
            }
            catch (System.Exception ex)
            {

            }

            //(二) 根據數據源的個數,設置重復變化的數據行組,
            //1 聲明與命名單元格相關的變量和數組
            int min_Row = 65536, min_COl = 65536, max_Row = 0;
            string min_Name = "";
            int nameCellCount = app.ActiveWorkbook.Names.Count;//獲得命名單元格的總數
            int[] nameCellRow = new int[nameCellCount];//某個命名單元格的行
            int[] nameCellColumn = new int[nameCellCount];//某個命名單元格的列
            string[] nameCellTag = new string[nameCellCount];//某個命名單元格的常規地址 ,比如 $A$1
            string[] nameCellName = new string[nameCellCount];//某個命名單元格的自定義名稱,比如 工資

            string strName, str;
            int row1, row2;//選擇重復的行
            int nameCellIdx = 0;

            //2 尋找所有命名的單元格,並找到行號最小者,以便在它之前插入循環行
            for (int k = 0; k < nameCellCount; k++)
            {
                strName = app.ActiveWorkbook.Names.Item(k + 1).Name;
                str = strName.Substring(0, 1);
                if (str == "_")
                {
                    continue;//如果第一個字符為下划線,則認為是固定命名單元格,不是命名的循環單元格
                }

                app.Goto(strName);
                nameCellColumn[nameCellIdx] = app.ActiveCell.Column;
                nameCellRow[nameCellIdx] = app.ActiveCell.Row;
                nameCellName[nameCellIdx] = strName;

                nameCellTag[nameCellIdx] = app.ActiveCell.Address;//$A$1
                nameCellTag[nameCellIdx] = nameCellTag[nameCellIdx].Split('$')[1];//$A$1--> A

                if (min_Row > nameCellRow[nameCellIdx])
                {
                    min_Row = nameCellRow[nameCellIdx];//最小的行號
                    min_COl = nameCellColumn[nameCellIdx];
                    min_Name = nameCellName[nameCellIdx];

                }
                if (max_Row < nameCellRow[nameCellIdx]) max_Row = nameCellRow[nameCellIdx]; ;//最大行號
                nameCellIdx++;//真實的循環的命名單元格序號

            }
            nameCellCount = nameCellIdx;//實際要處理的循環的命名單元格數目
            int loopRow = max_Row - min_Row + 1;//一次循環的函數
            //3 也可以使用 foreach ( Excel.Name  nn in app.ActiveWorkbook.Names)MessageBox.Show(nn.Name);
 
            //4 根據數據集的實際數據行數,查找命名單元格,循環插入數據
            for (int dt_row_idx = 0; dt_row_idx < dt.Rows.Count; dt_row_idx++)
            {//循環實際的數據行數

                //4.1 找到行號最小的循環行組的命名單元格,以它來定位
                app.Goto(min_Name);

                //4.2 //插入循環重復的摸板行組的行,使得所有命名單元格都向后移,以便下次循環查找定位使用
                for (int j = 0; j < loopRow; j++)
                {//插入需要重復循環的行數loopRow的空行
                    app.ActiveCell.EntireRow.Insert();
                }

                //4.3 定位到摸板行組首行
                app.Goto(min_Name);//轉到摸板行組的行號最小的命名單元格,以它來定位
                row1 = app.ActiveCell.Row;  //摸板行組的第一行
                row2 = row1 + loopRow - 1; //摸板行組的最后一行

                //4.4 復制整體模板的多行組,固定的摸板的格式和相關的文字說明,也可一個一個單元格復制
                ws.Range[ws.Cells[row1, 1], ws.Cells[row2, 255]].Copy();//整體多行組復制摸板行組

                //4.5 定位到新加入行的第一個單元格內
                row1 = row1 - loopRow;//向上回退到新加入的行組
                row2 = row2 - loopRow;
 
                //4.6 粘貼整體多行組,固定的摸板的格式和相關的文字說明
                ws.Range[ws.Cells[row1, 1], ws.Cells[row2, 255]].PasteSpecial();//整體多行組粘貼摸板行組

                //4.7 動態的數值加入
                for (int name_cell_idx = 0; name_cell_idx < nameCellCount; name_cell_idx++)
                {//循環命名單元格數量
                    //str = string.Format("{0}{1}", nameCellTag[name_cell_idx], nameCellRow[name_cell_idx]);
                    if (nameCellName[name_cell_idx].ToString() == "order_num")
                    {//序號
                        str = string.Format("{0}", dt_row_idx + 1);
                    }
                    else
                    {//以命名單元格的名稱,來取數據表行的對應字段的值
                        str = dt.Rows[dt_row_idx][nameCellName[name_cell_idx]].ToString();

                    }
                    //app.ActiveCell.FormulaR1C1 = str ;
                    ws.Cells[nameCellRow[name_cell_idx], nameCellColumn[name_cell_idx]] = str;
                    nameCellRow[name_cell_idx] += loopRow;//行號增加重復行的個數loopRow,准備下個循環,定位行使用
                }

            }
            // 5 刪除重復的摸板行,不再需要
            app.Goto(min_Name);//找到行號最小的命名單元格,以它來定位
            row1 = app.ActiveCell.Row;
            row2 = row1 + loopRow - 1;//選擇重復的行
            ws.Range[ws.Cells[row1, 1], ws.Cells[row2, 255]].Delete();

            //(三) 清除剪貼板,避免Excel關閉工作簿的時候出現提示
            //1 刪除剪切板的內容,防止退出提示
            //app.CutCopyMode = flase;//Excel.XlCutCopyMode.xlCut;//刪除剪切板的內容,防止退出提示
            //2 直接用range("A1").copy就行,不必把剪貼板都清空,這會影響其他進程的工作的
            ws.Range[ws.Cells[1, 1], ws.Cells[1, 1]].Copy();

            //(四) 結尾方面的工作
            try
            {//為了程序自動處理方便起見
                app.Goto("__結論");//結尾處的命名單元格,都以2個下划線__開頭
                app.ActiveCell.FormulaR1C1 = "成功完成";
            }
            catch (System.Exception ex)
            {

            }

        }
        public void InsertPictures(string Filename, Excel.Worksheet ws)//插入圖片
        {
            ws.Shapes.AddPicture(Filename, MsoTriState.msoFalse, MsoTriState.msoTrue, 10, 10, 150, 150);//后面的數字表示位置
        }
        public void InsertActiveChart(Excel.XlChartType ChartType, Excel.Worksheet ws, int DataSourcesX1, int DataSourcesY1, int DataSourcesX2, int DataSourcesY2, Excel.XlRowCol ChartDataType)//插入圖表操作
        {
            ChartDataType = Excel.XlRowCol.xlColumns;
            wb.Charts.Add(Type.Missing, Type.Missing, Type.Missing, Type.Missing);
            {
                wb.ActiveChart.ChartType = ChartType;
                wb.ActiveChart.SetSourceData(ws.get_Range(ws.Cells[DataSourcesX1, DataSourcesY1], ws.Cells[DataSourcesX2, DataSourcesY2]), ChartDataType);
                wb.ActiveChart.Location(Excel.XlChartLocation.xlLocationAsObject, ws);
            }
        }
        public bool SaveAs(object FileName)//文檔另存為
        {
            try
            {
                wb.SaveAs(FileName, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Excel.XlSaveAsAccessMode.xlExclusive, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
                return true;

            }
            catch (Exception ex)
            {
                return false;

            }
        }
        public void Close()//關閉一個Excel對象,銷毀對象
        {
            wb.Close(Type.Missing, Type.Missing, Type.Missing);
            wbs.Close();
            app.Quit();
            wb = null;
            wbs = null;
            app = null;
            GC.Collect();
        }
    }
//==
}

 

 

===============222222=======================

以下方法 將Excel模板文件存成 xml 格式的文本文件,從中把變化部分寫成特殊的標志,然后根據實際的數據替換即可。 保存html格式也可.

轉自網絡上
http://www.16aspx.com/Article/3793
無插件,無com組件,利用EXCEL、WORD模板做數據導出
  本次隨筆主要講述着工作中是如何解決數據導出的,對於數據導出到excel在日常工作中大家還是比較常用的,那導出到word呢,改如何處理呢,簡單的頁面導出問題應該不大,但是如果是標准的公文導出呢,要保證其基本格式,如紅頭、抬頭、文號等等格式的限制我們又該如何處理呢?

主要原理:

1、利用excel、word做好模板,在模板中設置關鍵字

2、在程序中調用模板,替換關鍵字

3、將替換后的模板作為導出文件輸出

一、導出到EXCEL,在此處先從簡單的入手,先描述如何利用excel做導出。步驟如下:

1、用excel2007隨便創建一個excel文件,打開添加如下數據:

c#操作Excel模板,替換命名單元格或關鍵字形成報表

2、點擊另存,將excel文件另存為xml格式文件,選擇2003xml格式,如下圖:

c#操作Excel模板,替換命名單元格或關鍵字形成報表

3、右鍵用記事本打開剛剛另存到xml文件,觀察xml內容會發現其妙之處,如下圖:

c#操作Excel模板,替換命名單元格或關鍵字形成報表

  如上圖所示,注意觀察,每一個WorkSheet都用了一段xml代碼來表示,方框部分為我們寫入的數據,圓圈部分為我們要處理的重要部分。

  小圓圈內的2表示當前數據2行,大圓圈表示我們看到的三行三列數據,因此我們要做的就是將我們要導出到數據寫成圓圈中的格式就行了。

4、改進xml文件,創建關鍵字,如下圖:


c#操作Excel模板,替換命名單元格或關鍵字形成報表

  如上圖所示,我們創建了兩個關鍵字,具體含義不多說。

  最后將創建好的xml文件,也就是你的excel模板可以放入到項目中了,接下來要做的就是將數據生成並按照標准格式輸出,進行替換關鍵字即可。

5、數據生成並輸出,如下所示:

public byte[] GetData(string path, string tempName)
        {
            //實例化內存流
            MemoryStream fileStream = new MemoryStream();
            //寫文件流
            StreamWriter fileWriter = new StreamWriter(fileStream);
            //讀文件流
            StreamReader fileReader = new StreamReader(path, System.Text.Encoding.UTF8);
            //讀取整個文件的內容
            string tempStr = fileReader.ReadToEnd();
            //得到要導出的信息
            DataTable dt = airport.GetDataView();
            //定義變量獲取表的數據行數
            int rows = 0;
            //定義StringBuilder變量來存儲字符串
            StringBuilder sb = new StringBuilder();
            //判斷表是否有數據
            if (dt != null && dt.Rows.Count > 0)
            {
                //給變量賦值
                rows = dt.Rows.Count;
                int num = rows + 1;//此處1表示模板中表頭的行數,且默認為1,可自行增加表頭並定義
                if (tempStr.IndexOf("+#RowCount#+") > 0)
                {
                    tempStr = tempStr.Replace("+#RowCount#+", "" + num + "");
                }
                //開始循環生成標准字符串
                for (int i = 0; i < rows; i++)
                {
                    sb.Append("\n"
                        + "" + dt.Rows[i]["Name"] + "\n"
                        + "" + dt.Rows[i]["Sex"] + "\n"
                        + "" + dt.Rows[i]["Age"] + "\n"
                        + "\n");
                }
                if (tempStr.IndexOf("+�ta%+") > 0)
                {
                    tempStr = tempStr.Replace("+�ta%+", sb.ToString());
                }
            }
            fileWriter.WriteLine(tempStr);
            fileWriter.Flush();

            byte[] bytes = fileStream.ToArray();

            fileStream.Close();
            fileWriter.Close();
            fileReader.Close();

            return bytes;
        }如上所示,創建獲取數據,並返回我們要輸出的字符串,並轉成二進制流,具體操作因人而異。接下來調用此方法替換數據,並輸出excel新文件。

protected void btnExport_Click(object sender, EventArgs e)
        {
            byte[] bytes = GetData(Server.MapPath("xml模板的路徑"), "");

            //實現下載
            Response.AddHeader("Content-Type", "application/octet-stream");
            Response.Buffer = true;
            Response.ContentType = "*/*";
            Response.AddHeader("Content-Disposition", "attachment;filename=" + System.Web.HttpUtility.UrlEncode("導出的文件.xls", System.Text.Encoding.UTF8));
            Response.AddHeader("Content-Length", bytes.Length.ToString());
            Response.BinaryWrite(bytes);
            Response.End();

        }總上所述,一個完成的數據導出到EXCEL就完成了。
優點:

1、可以導出任何你可以在excel中能模擬出來的數據樣式,包括圖形嵌入。在后一篇會講解如何導出圖片到excel,word。

2、整個過程不復雜,不需要調用插件、office組件,BS或者CS模式的方式都適用,沒有復雜的邏輯過程。

3、解決多sheet導出數據。

缺點:需要先做模板

注意事項:模板中的關鍵字要根據數據內容而定,不要出現關鍵字沖突的情況,關鍵字字符標准由開發者自行定奪。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM