1. 程式人生 > 其它 >C#如何定製Excel介面並實現與資料庫互動

C#如何定製Excel介面並實現與資料庫互動

Excel是微軟辦公套裝軟體的一個重要的組成部分,它可以進行各種資料的處理、統計分析和輔助決策操作,廣泛地應用於管理、統計財經、金融等眾多領域。(另外,Excel還是倫敦一所會展中心的名稱)。.NET可以建立Excel Add-In對Excel進行功能擴充套件,這些擴充套件的功能包括自定義使用者函式,自定義UI,與資料庫進行資料互動等。

一 主要的Excel開發方式

1 VBA

VBA是一種Visual Basic的巨集語言,它是最早的Office提供定製化的一種解決方案,VBA是VB的一個子集,和Visual Basic不同,VBA是一種宿主型語言,無論是專業的開發人員,還是剛入門的非開發人員,都可以利用VBA完成簡單或複雜的需求。

2 Excel 外掛

Excel Addin,就像Visual Studio外接外掛一樣,也可以使用一些技術為Office開發一些外掛。對VBA的一些問題,一些專業的開發人員,可以使用 VisualBasic或者VisualC++等工具來引用Office的一些dll,來針對Office進行開發。開發的時候將dll註冊為com組 件,並在登錄檔裡面進行註冊,這樣就可以在Excel裡直接呼叫這些外掛。

3 VSTO(Office 的 Visual Studio 工具)

VSTO主要是對Office的一些dll進行了.NET封裝,使得我們可以使用.NET上的語言來方便的對Office的一些方法進行呼叫。所 以,Office開發跨入了一個新的時代,開發人員可以使用更加高階的語言和熟悉的技術來更容易的進行Office開發。對於企業及的應用和開發,VSTO或許是首要選擇,他極大地擴充套件了Office應用程式的能力,使用.NET平臺支援的程式語言,能夠直接訪問.NET上面眾多的類庫。具有較好的安全機制。簡化了Office外掛的開發和部署。

4 XLL

XLL是Excel的一種外接應用程式,他使用C和C++開發,程式通過呼叫Excel暴漏的C介面來實現擴充套件功能。這種方式開發的應用程式效率高,但是難度大,對開發者自身的要求較高。開源專案Excel-DNA就是使用XLL技術開發的,能夠幫助.NET 開發人員來極大地簡化RTD函式,同步、非同步UDF函式的編寫和開發。

5 OpenXML

如果使用者沒有安裝Excel應用程式,或者在伺服器端需要動態生成Excel檔案的時候。我們可能需要直接讀取或者生成Excel檔案,這種情況下,如果要對Excel檔案進行各種定製化開發的話,建議使用OpenXML。NPOI開源專案可以直接讀寫Excel檔案,而且相容多個版本。

二 使用Excel Add-In構建擴充套件

  開發環境: 作業系統為Windows Server 2008R2 x64;Excel為Excel 2010 x64;開發工具為Visual Studio 2012旗艦版x64;資料庫為SQL Server 2008R2 x64.

  1 程式結構

  用Visual Studio 2012新建一個ExcelAddInDemo的Excel Add-In專案,並新增若干檔案,程式結構如下圖:

  其中,RibbonAddIn可以定製2010的UI面板,SqlHelper.cs是一個簡單的資料庫訪問幫助類,UClog.cs,UCPaneLeft.cs,UCTaskGrid.cs,UCTaskPane.cs都為新增的自定義控制元件,並通過程式新增到EXCEL介面中.執行起來的介面如下:

  程式可以通過在Excel介面中輸入ID,First,Last,Email的值(對應標籤的後一個單元格),單擊使用者列表面板上的儲存按鈕,將資料儲存到資料庫中.

  2 RibbonAddIn設計

  我們通過RibbonAddIn.cs給Excel的Ribbon添加了一個名為CUMT的外掛.RibbonAddIn面板可以通過工具條控制元件方便的拖放到設計介面上.RibbonAddIn.cs的屬性設定如下圖所示:

  後臺程式碼如下:

1  使用 系統; 
 2  使用 System.Collections.Generic; 
 3  使用 System.Linq; 
 4  使用 System.Text; 
 5  使用 Microsoft.Office.Tools.Ribbon; 
 6  
7  名稱空間 ExcelAddInDemo 
 8  { 
 9      公共  部分  RibbonAddIn 
 10  { 
 11          
12          private  void RibbonAddIn_Load( 物件 傳送者,RibbonUIEventArgs e) 
 13  { 
 14            
15  } 
 16  
17          private  void btnAbout_Click( 物件 傳送者,RibbonControlEventArgs e) 
 18  { 
 19 System.Windows.Forms.MessageBox.Show( JackWangCUMT! ); 
 20  } 
 21  
22          private  void btnShow_Click( 物件 傳送者,RibbonControlEventArgs e) 
 23  { 
 24              if (Globals.ThisAddIn._MyCustomTaskPane != null ) 
 25  { 
 26 Globals.ThisAddIn._MyCustomTaskPane.Visible = true ; 
 27  } 
 28  } 
 29  
30          private  void btnHide_Click( 物件 傳送者,RibbonControlEventArgs e) 
 31  { 
 32              if (Globals.ThisAddIn._MyCustomTaskPane != null ) 
 33  { 
 34 Globals.ThisAddIn._MyCustomTaskPane.Visible = false ; 
 35  } 
 36  } 
 37  } 
 38 } 

  3ThisAddIn邏輯編寫

1  使用 系統; 
 2  使用 System.Collections.Generic; 
 3  使用 System.Linq; 
 4  使用 System.Text; 
 5  使用 System.Xml.Linq; 
 6  使用 Excel = Microsoft.Office.Interop.Excel; 
 7  名稱空間 ExcelAddInDemo 
 8  { 
 9      使用 Microsoft.Office.Tools; 
 10      公共  部分  ThisAddIn 
 11  { 
 12          公共 CustomTaskPane _MyCustomTaskPane = null ; 
 13      
14          private  void ThisAddIn_Startup( 物件 傳送者,System.EventArgs e) 
 15  { 
 16 UCTaskPane taskPane = new UCTaskPane(); 
 17 _MyCustomTaskPane = this .CustomTaskPanes.Add(taskPane, " 我的任務面板 " ); 
 18 _MyCustomTaskPane.Width = 30 ; // height 有問題,此處width ==height 
19 _MyCustomTaskPane.Visible = true ; 
 20 _MyCustomTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionTop; 
 21  
22 UCPaneLeft panLeft = new UCPaneLeft(); 
 23 _MyCustomTaskPane = this .CustomTaskPanes.Add(panLeft, " 組織 " ); 
 24 _MyCustomTaskPane.Width = 200 ; 
 25 _MyCustomTaskPane.Visible = true ; 
 26 _MyCustomTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionLeft; 
 27  
28 UCTaskGrid panRight = new UCTaskGrid(); 
 29 _MyCustomTaskPane = this .CustomTaskPanes.Add(panRight, " 使用者列表 " ); 
 30 _MyCustomTaskPane.Width = 200 ; 
 31 _MyCustomTaskPane.Visible = true ; 
 32 _MyCustomTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionRight; 
 33  
34 UCLog panLog = new UCLog(); 
 35 _MyCustomTaskPane = this .CustomTaskPanes.Add(panLog, " 日誌列表 " ); 
 36 _MyCustomTaskPane.Width = 60 ; 
 37 _MyCustomTaskPane.Visible = true ; 
 38 _MyCustomTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionBottom; 
 39  
40              // 掛鉤工作簿開啟事件 
 41              // 這是因為執行此方法時,Office 並不總是準備好文件 
42              this .Application.WorkbookActivate += Application_WorkbookActivate; 
 43              // 測試  
 44              // this.Application.SheetSelectionChange += Application_SheetSelectionChange; 
45  } 
 46  
47          void Application_SheetSelectionChange( object Sh, Excel.Range Target) 
 48  { 
 49              如果 ( 這個 .Application != null 50  { 
 51                  this .Application.Caption = this .Application.ActiveCell.Address.ToString(); // 1 澳元 
 52                  // + this.Application.ActiveCell.AddressLocal.ToString(); // 1 澳元 
 53                  // this.Application.ActiveCell.Formula = "=sum(1+2)"; 
54                
55  } 
 56  } 
 57  
58          無效 Application_WorkbookActivate(Excel.Workbook Wb) 
 59  { 
 60              // using Microsoft.Office.Tools.Excel 和 using Microsoft.Office.Interop.Excel 等,容易重新調整 
 61              // 字串路徑 = this.Application.ActiveWorkbook.FullName; 
62 Excel._Worksheet ws = (Excel._Worksheet) this .Application.ActiveWorkbook.ActiveSheet; 
 63 ws.Cells[ 2 , 2 ] = " ID2 " ; 
 64              // 如何設定只讀等有待研究 
65              int r= 2 ,c= 2 ; 
 66             // ((Excel.Range)ws.Cells[r, c]).NumberFormat = format; 
67 ((Excel.Range)ws.Cells[r, c]).Value2 = " ID " ; 
 68 ((Excel.Range)ws.Cells[r, c]).Interior.Color = System.Drawing。 ColorTranslator.ToOle(System.Drawing.Color.Red); 
 69              // ((Excel.Range)ws.Cells[r, c]).Style.Name = "Normal"; 
70 ((Excel.Range)ws.Cells[r, c]).Style.Font.Bold = true ; 
 71  
72              #region 格式 
 73 ((Microsoft.Office.Interop.Excel.Range)ws.get_Range( " A2 " , " E10 " )).Font.Bold = true ; 
 74 ((Microsoft.Office.Interop.Excel.Range)ws.get_Range( " A2 " , " E10 " )).Font.Italic = true ; 
 75 ((Microsoft.Office.Interop.Excel.Range)ws.get_Range( " A2 " , " E10 " )).Font.Color = System.Drawing.Color.FromArgb( 96 , 32 , 0 ).ToArgb(); 
 76 ((Microsoft.Office.Interop.Excel.Range)ws.get_Range( " A2 " , " E10 " )).Font.Name = " Calibri " ; 
 77 ((Microsoft.Office.Interop.Excel.Range)ws.get_Range( " A2 " , " E10 " )).Font.Size = 15 ; 
 78  
79              // 邊框 
80 Excel.Range range = ((Microsoft.Office.Interop.Excel.Range)ws.get_Range( " B2 " , " E3 " )); 
 81 精益求精。 邊框 border = range.Borders; 
 82 邊框[Excel.XlBordersIndex.xlEdgeBottom].LineStyle = Excel。 XlLineStyle.xlContinuous; 
 83 border.Weight = 2d; 
 84 邊框[Excel.XlBordersIndex.xlEdgeTop].LineStyle = Excel.XlLineStyle.xlContinuous; 
 85 邊框[Excel.XlBordersIndex.xlEdgeLeft].LineStyle = Excel.XlLineStyle.xlContinuous; 
 86 邊框[Excel.XlBordersIndex.xlEdgeRight].LineStyle = Excel.XlLineStyle.xlContinuous; 
 87              #endregion 
88 ws.Cells[ 2 , 4 ] = " First " ; 
 89個 ws.Cells [ 3 , 2 ] = 上次 ; 
 90 ws.Cells[ 3 , 4 ] = " 電子郵件 " ; 
 91  } 
 92          私有  無效 ThisAddIn_Shutdown( 物件 傳送者,System.EventArgs e) 
 93  { 
 94  } 
 95  
96          #region VSTO生成的程式碼 
 97  
98          ///  <summary> 
99          /// 設計器支援需要的方法 - 不要 
 100          /// 使用程式碼編輯器修改此方法的內容。 
 101          ///  </summary> 
102          私有  無效 內部啟動() 
 103  { 
 104              this .Startup += new System.EventHandler(ThisAddIn_Startup); 
 105              this .Shutdown += new System.EventHandler(ThisAddIn_Shutdown); 
 106  } 
 107          
108          #endregion 
109  } 
 110 } 

  ThisAddIn_Startup事件中,初始化四個面板,並對其基本屬性進行設定,停靠在上的面板我設定其Height無效,改成Width後其效果和Height預期的一樣(不知道這個底層開發人員是怎麼想的,哈哈!)另外 Excel._Worksheet ws = (Excel._Worksheet)this.Application.ActiveWorkbook.ActiveSheet;是非常關鍵的一句,我這裡足足折騰了很久,原因是using Microsoft.Office.Tools.Excel 和 using Microsoft.Office.Interop.Excel 都有worksheet元素,結構混淆了,執行時老是獲取不到Excel的ActiveWorkbook.

  4UCTaskGrid設計

  UCTaskGrid是一個使用者控制元件,包含一個工具條和一個dataGridView1控制元件,其設計介面如下:

  後臺程式碼如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.ComponentModel;
 4 using System.Drawing;
 5 using System.Data;
 6 using System.Linq;
 7 using System.Text;
 8 using System.Windows.Forms;
 9 
10 namespace ExcelAddInDemo
11 {
12     using Excel = Microsoft.Office.Interop.Excel;
13     public partial class UCTaskGrid : UserControl
14     {
15         public UCTaskGrid()
16         {
17             InitializeComponent();
18         }
19 
20         private void UCTaskGrid_Load(object sender, EventArgs e)
21         {
22             //load data
23             System.Data.DataTable dt = SqlHelper.getDateTable("select * from ACT_ID_USER", null);
24             this.dataGridView1.DataSource = dt;
25         }
26 
27         private void 儲存SToolStripButton_Click(object sender, EventArgs e)
28         {
29             //核心程式碼,獲取當前的worksheet
30             Excel._Worksheet ws = (Excel._Worksheet)Globals.ThisAddIn.Application.ActiveWorkbook.ActiveSheet;
31             string name = ws.Name;
32             string ID = ((string)(ws.Cells[2, 5] as Excel.Range).Value).ToString();
33             string First = ((string)(ws.Cells[2, 5] as Excel.Range).Value).ToString();
34             string Last = ((string)(ws.Cells[3, 3] as Excel.Range).Value).ToString();
35             string Email = ((string)(ws.Cells[3, 5] as Excel.Range).Value).ToString();
36             string sql = string.Format("insert into ACT_ID_USER ([ID_],[FIRST_],[LAST_],[EMAIL_]) values('{0}','{1}','{2}','{3}')", ID, First, Last, Email);
37             int rows= SqlHelper.ExecuteNonQuery(SqlHelper.ConnectionStringLocalTransaction, System.Data.CommandType.Text,sql,null);
38             if (rows == 1)
39             {
40                 System.Windows.Forms.MessageBox.Show("saved");
41             }
42             else
43             {
44                 System.Windows.Forms.MessageBox.Show("error");
45             }
46 
47         }
48 
49         private void 開啟OToolStripButton_Click(object sender, EventArgs e)
50         {
51             //refresh
52             System.Data.DataTable dt = SqlHelper.getDateTable("select * from ACT_ID_USER", null);
53             this.dataGridView1.DataSource = dt;
54         }
55     }
56 }

  5 Add-In強簽名

  通過設定程式的屬性中的簽名頁,讓VS自動生成一個簽名即可(需設定密碼)

三 最終效果演示

  為了直觀的展示,看下面的動畫:

四 猜想Excel Service

  現在功能很強大的Excel伺服器,其中一個亮點就是在Excel中進行介面設計和資料操作,然後就資料持久化到資料庫中,那麼我的猜想是,能不能通過AddIn的方式實現一個excel service功能呢,將介面設計序列化儲存到資料庫中,並給一個路徑(唯一),但使用者單擊選單(確定了路徑)後將介面設計呈現到excel中,然後使用者操作完成後,通過後臺程式將資料儲存到資料庫中.

水平有限,望各位園友不吝賜教!如果覺得不錯,請點選推薦和關注!
出處: http://www.cnblogs.com/isaboy/
宣告:本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。