C#定制Excel界面并實現(xiàn)與數(shù)據(jù)庫交互的方法
Excel是微軟辦公套裝軟件的一個重要的組成部分,它可以進行各種數(shù)據(jù)的處理、統(tǒng)計分析和輔助決策操作,廣泛地應(yīng)用于管理、統(tǒng)計財經(jīng)、金融等眾多領(lǐng)域。(另外,Excel還是倫敦一所會展中心的名稱)。.NET可以創(chuàng)建Excel Add-In對Excel進行功能擴展,這些擴展的功能包括自定義用戶函數(shù),自定義UI,與數(shù)據(jù)庫進行數(shù)據(jù)交互等。
一 主要的Excel開發(fā)方式
1 VBA
VBA是一種Visual Basic的宏語言,它是最早的Office提供定制化的一種解決方案,VBA是VB的一個子集,和Visual Basic不同,VBA是一種宿主型語言,無論是專業(yè)的開發(fā)人員,還是剛?cè)腴T的非開發(fā)人員,都可以利用VBA完成簡單或復(fù)雜的需求。
2 Excel Addin
Excel Addin,就像Visual Studio外接插件一樣,也可以使用一些技術(shù)為Office開發(fā)一些插件。對VBA的一些問題,一些專業(yè)的開發(fā)人員,可以使用 VisualBasic或者VisualC++等工具來引用Office的一些dll,來針對Office進行開發(fā)。開發(fā)的時候?qū)ll注冊為com組 件,并在注冊表里面進行注冊,這樣就可以在Excel里直接調(diào)用這些插件。
3 VSTO (Visual Studio Tools for Office)
VSTO主要是對Office的一些dll進行了.NET封裝,使得我們可以使用.NET上的語言來方便的對Office的一些方法進行調(diào)用。所 以,Office開發(fā)跨入了一個新的時代,開發(fā)人員可以使用更加高級的語言和熟悉的技術(shù)來更容易的進行Office開發(fā)。 對于企業(yè)及的應(yīng)用和開發(fā),VSTO或許是首要選擇,他極大地擴展了Office應(yīng)用程序的能力,使用.NET平臺支持的編程語言,能夠直接訪問.NET上面眾多的類庫。具有較好的安全機制。簡化了Office插件的開發(fā)和部署。
4 XLL
XLL是Excel的一種外接應(yīng)用程序,他使用C和C++開發(fā),程序通過調(diào)用Excel暴漏的C接口來實現(xiàn)擴展功能。這種方式開發(fā)的應(yīng)用程序效率高,但是難度大,對開發(fā)者自身的要求較高。開源項目Excel-DNA就是使用XLL技術(shù)開發(fā)的,能夠幫助.NET 開發(fā)人員來極大地簡化RTD函數(shù),同步、異步UDF函數(shù)的編寫和開發(fā)。
5 OpenXML
如果用戶沒有安裝Excel應(yīng)用程序,或者在服務(wù)器端需要動態(tài)生成Excel文件的時候。我們可能需要直接讀取或者生成Excel文件,這種情況下,如果要對Excel文件進行各種定制化開發(fā)的話,建議使用OpenXML。NPOI開源項目可以直接讀寫Excel文件,而且兼容多個版本。
二 使用Excel Add-In構(gòu)建擴展
開發(fā)環(huán)境: 操作系統(tǒng)為Windows Server 2008R2 x64;Excel為Excel 2010 x64;開發(fā)工具為Visual Studio 2012旗艦版x64;數(shù)據(jù)庫為SQL Server 2008R2 x64.
1 程序結(jié)構(gòu)
用Visual Studio 2012新建一個ExcelAddInDemo的Excel Add-In項目,并添加若干文件,程序結(jié)構(gòu)如下圖:
其中,RibbonAddIn可以定制2010的UI面板,SqlHelper.cs是一個簡單的數(shù)據(jù)庫訪問幫助類,UClog.cs,UCPaneLeft.cs,UCTaskGrid.cs,UCTaskPane.cs都為添加的自定義控件,并通過程序添加到EXCEL界面中.運行起來的界面如下:
程序可以通過在Excel界面中輸入ID,First,Last,Email的值(對應(yīng)標簽的后一個單元格),單擊用戶列表面板上的保存按鈕,將數(shù)據(jù)保存到數(shù)據(jù)庫中.
2 RibbonAddIn設(shè)計
我們通過RibbonAddIn.cs給Excel的Ribbon添加了一個名為CUMT的插件.RibbonAddIn面板可以通過工具條控件方便的拖放到設(shè)計界面上.RibbonAddIn.cs的屬性設(shè)置如下圖所示:
后臺代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Office.Tools.Ribbon; namespace ExcelAddInDemo { public partial class RibbonAddIn { private void RibbonAddIn_Load(object sender, RibbonUIEventArgs e) { } private void btnAbout_Click(object sender, RibbonControlEventArgs e) { System.Windows.Forms.MessageBox.Show("JackWangCUMT!"); } private void btnShow_Click(object sender, RibbonControlEventArgs e) { if (Globals.ThisAddIn._MyCustomTaskPane != null) { Globals.ThisAddIn._MyCustomTaskPane.Visible = true; } } private void btnHide_Click(object sender, RibbonControlEventArgs e) { if (Globals.ThisAddIn._MyCustomTaskPane != null) { Globals.ThisAddIn._MyCustomTaskPane.Visible = false; } } } }
3 ThisAddIn邏輯編寫
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Linq; using Excel = Microsoft.Office.Interop.Excel; namespace ExcelAddInDemo { using Microsoft.Office.Tools; public partial class ThisAddIn { public CustomTaskPane _MyCustomTaskPane = null; private void ThisAddIn_Startup(object sender, System.EventArgs e) { UCTaskPane taskPane = new UCTaskPane(); _MyCustomTaskPane = this.CustomTaskPanes.Add(taskPane, "我的任務(wù)面板"); _MyCustomTaskPane.Width = ;//height有問題,此處width ==height _MyCustomTaskPane.Visible = true; _MyCustomTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionTop; UCPaneLeft panLeft = new UCPaneLeft(); _MyCustomTaskPane = this.CustomTaskPanes.Add(panLeft, "組織"); _MyCustomTaskPane.Width = ; _MyCustomTaskPane.Visible = true; _MyCustomTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionLeft; UCTaskGrid panRight = new UCTaskGrid(); _MyCustomTaskPane = this.CustomTaskPanes.Add(panRight, "用戶列表"); _MyCustomTaskPane.Width = ; _MyCustomTaskPane.Visible = true; _MyCustomTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionRight; UCLog panLog = new UCLog(); _MyCustomTaskPane = this.CustomTaskPanes.Add(panLog, "日志列表"); _MyCustomTaskPane.Width = ; _MyCustomTaskPane.Visible = true; _MyCustomTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionBottom; //Hook into the workbook open event //This is because Office doesn't always have a document ready when this method is run this.Application.WorkbookActivate += Application_WorkbookActivate; //test //this.Application.SheetSelectionChange += Application_SheetSelectionChange; } void Application_SheetSelectionChange(object Sh, Excel.Range Target) { if (this.Application != null) { this.Application.Caption = this.Application.ActiveCell.Address.ToString();//$A$ //+ this.Application.ActiveCell.AddressLocal.ToString();//$A$ //this.Application.ActiveCell.Formula = "=sum(+)"; } } void Application_WorkbookActivate(Excel.Workbook Wb) { //using Microsoft.Office.Tools.Excel 和 using Microsoft.Office.Interop.Excel 都有worksheet等,容易混淆 //string path = this.Application.ActiveWorkbook.FullName; Excel._Worksheet ws = (Excel._Worksheet)this.Application.ActiveWorkbook.ActiveSheet; ws.Cells[, ] = "ID"; //如何設(shè)置只讀等有待研究 int r=,c=; //((Excel.Range)ws.Cells[r, c]).NumberFormat = format; ((Excel.Range)ws.Cells[r, c]).Value = "ID"; ((Excel.Range)ws.Cells[r, c]).Interior.Color =System.Drawing. ColorTranslator.ToOle(System.Drawing.Color.Red); //((Excel.Range)ws.Cells[r, c]).Style.Name = "Normal"; ((Excel.Range)ws.Cells[r, c]).Style.Font.Bold = true; #region format ((Microsoft.Office.Interop.Excel.Range)ws.get_Range("A", "E")).Font.Bold = true; ((Microsoft.Office.Interop.Excel.Range)ws.get_Range("A", "E")).Font.Italic = true; ((Microsoft.Office.Interop.Excel.Range)ws.get_Range("A", "E")).Font.Color = System.Drawing.Color.FromArgb(, , ).ToArgb(); ((Microsoft.Office.Interop.Excel.Range)ws.get_Range("A", "E")).Font.Name = "Calibri"; ((Microsoft.Office.Interop.Excel.Range)ws.get_Range("A", "E")).Font.Size = ; //border Excel.Range range = ((Microsoft.Office.Interop.Excel.Range)ws.get_Range("B", "E")); Excel. Borders border = range.Borders; border[Excel.XlBordersIndex.xlEdgeBottom].LineStyle =Excel. XlLineStyle.xlContinuous; border.Weight = d; border[Excel.XlBordersIndex.xlEdgeTop].LineStyle = Excel.XlLineStyle.xlContinuous; border[Excel.XlBordersIndex.xlEdgeLeft].LineStyle = Excel.XlLineStyle.xlContinuous; border[Excel.XlBordersIndex.xlEdgeRight].LineStyle = Excel.XlLineStyle.xlContinuous; #endregion ws.Cells[, ] = "First"; ws.Cells[, ] = "Last"; ws.Cells[, ] = "Email"; } private void ThisAddIn_Shutdown(object sender, System.EventArgs e) { } #region VSTO 生成的代碼 /// <summary> /// 設(shè)計器支持所需的方法 - 不要 /// 使用代碼編輯器修改此方法的內(nèi)容。 /// </summary> private void InternalStartup() { this.Startup += new System.EventHandler(ThisAddIn_Startup); this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown); } #endregion } }
ThisAddIn_Startup事件中,初始化四個面板,并對其基本屬性進行設(shè)置,??吭谏系拿姘逦以O(shè)置其Height無效,改成Width后其效果和Height預(yù)期的一樣(不知道這個底層開發(fā)人員是怎么想的,哈哈!)另外 Excel._Worksheet ws = (Excel._Worksheet)this.Application.ActiveWorkbook.ActiveSheet;是非常關(guān)鍵的一句,我這里足足折騰了很久,原因是using Microsoft.Office.Tools.Excel 和 using Microsoft.Office.Interop.Excel 都有worksheet元素,結(jié)構(gòu)混淆了,運行時老是獲取不到Excel的ActiveWorkbook.
4 UCTaskGrid設(shè)計
UCTaskGrid是一個用戶控件,包含一個工具條和一個dataGridView1控件,其設(shè)計界面如下:
后臺代碼如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; namespace ExcelAddInDemo { using Excel = Microsoft.Office.Interop.Excel; public partial class UCTaskGrid : UserControl { public UCTaskGrid() { InitializeComponent(); } private void UCTaskGrid_Load(object sender, EventArgs e) { //load data System.Data.DataTable dt = SqlHelper.getDateTable("select * from ACT_ID_USER", null); this.dataGridView.DataSource = dt; } private void 保存SToolStripButton_Click(object sender, EventArgs e) { //核心代碼,獲取當前的worksheet Excel._Worksheet ws = (Excel._Worksheet)Globals.ThisAddIn.Application.ActiveWorkbook.ActiveSheet; string name = ws.Name; string ID = ((string)(ws.Cells[, ] as Excel.Range).Value).ToString(); string First = ((string)(ws.Cells[, ] as Excel.Range).Value).ToString(); string Last = ((string)(ws.Cells[, ] as Excel.Range).Value).ToString(); string Email = ((string)(ws.Cells[, ] as Excel.Range).Value).ToString(); string sql = string.Format("insert into ACT_ID_USER ([ID_],[FIRST_],[LAST_],[EMAIL_]) values('{}','{}','{}','{}')", ID, First, Last, Email); int rows= SqlHelper.ExecuteNonQuery(SqlHelper.ConnectionStringLocalTransaction, System.Data.CommandType.Text,sql,null); if (rows == ) { System.Windows.Forms.MessageBox.Show("saved"); } else { System.Windows.Forms.MessageBox.Show("error"); } } private void 打開OToolStripButton_Click(object sender, EventArgs e) { //refresh System.Data.DataTable dt = SqlHelper.getDateTable("select * from ACT_ID_USER", null); this.dataGridView.DataSource = dt; } } }
5 Add-In強簽名
通過設(shè)置程序的屬性中的簽名頁,讓VS自動生成一個簽名即可(需設(shè)置密碼)
三 最終效果演示
為了直觀的展示,看下面的動畫:
四 猜想 Excel Service
現(xiàn)在功能很強大的Excel服務(wù)器,其中一個亮點就是在Excel中進行界面設(shè)計和數(shù)據(jù)操作,然后就數(shù)據(jù)持久化到數(shù)據(jù)庫中,那么我的猜想是,能不能通過AddIn的方式實現(xiàn)一個excel service功能呢,將界面設(shè)計序列化保存到數(shù)據(jù)庫中,并給一個路徑(唯一),但用戶單擊菜單(確定了路徑)后將界面設(shè)計呈現(xiàn)到excel中,然后用戶操作完成后,通過后臺程序?qū)?shù)據(jù)庫保存到數(shù)據(jù)庫中.
- c#將Excel數(shù)據(jù)導(dǎo)入到數(shù)據(jù)庫的實現(xiàn)代碼
- C#數(shù)據(jù)導(dǎo)入/導(dǎo)出Excel文件及winForm導(dǎo)出Execl總結(jié)
- c#利用Excel直接讀取數(shù)據(jù)到DataGridView
- C#連接Excel2003和Excel2007以上版本做數(shù)據(jù)庫的連接字符串
- C#導(dǎo)出數(shù)據(jù)到Excel文件的方法
- C#操作Excel數(shù)據(jù)增刪改查示例
- C#將Sql數(shù)據(jù)保存到Excel文件中的方法
- C#自定義導(dǎo)出數(shù)據(jù)到Excel的類實例
- C#利用Openxml讀取Excel數(shù)據(jù)實例
- C#如何操作Excel數(shù)據(jù)透視表
相關(guān)文章
基于C#中IDisposable與IEnumerable、IEnumerator的應(yīng)用
本篇文章小編為大家介紹,基于C#中IDisposable與IEnumerable、IEnumerator的應(yīng)用,需要的朋友參考下2013-04-04WPF實現(xiàn)XAML轉(zhuǎn)圖片的示例詳解
這篇文章主要為大家詳細介紹了如何利用WPF實現(xiàn)XAML轉(zhuǎn)圖片,文中的示例代碼講解詳細,對我們學(xué)習或工作有一定幫助,感興趣的小伙伴可以了解一下2022-11-11C# TabControl控件中TabPage選項卡切換時的觸發(fā)事件問題
這篇文章主要介紹了C# TabControl控件中TabPage選項卡切換時的觸發(fā)事件問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04C#實現(xiàn)應(yīng)用程序的監(jiān)控與調(diào)試的示例代碼
日志記錄是軟件開發(fā)中不可或缺的功能,它能幫助開發(fā)者在應(yīng)用程序運行時記錄重要信息,本文就來介紹一下常用日志記錄功能以及常用的日志庫,感興趣的可以了解一下2024-03-03C++聯(lián)合體轉(zhuǎn)換成C#結(jié)構(gòu)的實現(xiàn)方法
這篇文章主要介紹了C++聯(lián)合體轉(zhuǎn)換成C#結(jié)構(gòu)的實現(xiàn)方法,需要的朋友可以參考下2014-08-08