文章目錄
- 前言
- 一、第一坑:安裝offic2007后excel加載項找不到了
- 二、示例1 通過Ribbon XML自定義Excel主菜單并添加新項
- 二、示例1 總結
- 三、示例2 創建VSTO外接程序
- 三、示例2 總結
- 四、示例 3 C# VSTO外接程序示例
- 四、示例 3 總結
- 五、實現C# 的VSTO調用VBA函數(xlam)
- 六、結語
前言
這幾天玩VBA,
嘗試XML繪制EXCEL主菜單,注入EXCEL,并調用VBA的函數。
眾所周知VS的IDE是多強大,我就尋思能不能用C#畫界面去控制VBA的插件。這樣更新就能單xlam覆蓋更新了。
然后開始學習VS的 VSTO外接程序,確實很有意思。
一、第一坑:安裝offic2007后excel加載項找不到了
至于為什么使用2007,我尋思07上能跑的13、16不得兼任啊。我用13的開發,還得倒回來弄07、10的兼容不是。
二、示例1 通過Ribbon XML自定義Excel主菜單并添加新項
步驟1:創建Ribbon XML定義文件
新建一個XML文件(如customUI.xml),定義以下結構
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui"><ribbon><tabs><tab id="CustomTab" label="我的工具"><group id="CustomGroup" label="數據處理"><button id="btnCleanData" label="數據清洗" size="large" onAction="DataCleaningMacro"imageMso="DataRefreshAll" /><menu id="mnuAdvanced" label="高級操作" imageMso="GroupEdit"><button id="btnMerge" label="合并工作表" onAction="MergeSheetsMacro"/><button id="btnSplit" label="拆分數據" onAction="SplitDataMacro"/></menu></group></tab></tabs></ribbon>
</customUI>
關鍵參數說明:
imageMso:使用Office內置圖標(如DataRefreshAll代表刷新圖標)3
onAction:綁定VBA回調函數
步驟2:將XML集成到Excel文件
將Excel文件后綴改為.zip
在壓縮包內創建路徑:customUI/_rels
將customUI.xml放入customUI文件夾
創建關系文件customUI/_rels/customUI.xml.rels:
<?xml version="1.0" encoding="UTF-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Type="http://schemas.microsoft.com/office/2006/relationships/ui/extensibility" Target="/customUI/customUI.xml" Id="RibbonCustomization" />
</Relationships>
步驟3:編寫VBA回調函數
在Excel的VBA編輯器中添加模塊(需啟用宏):
' 按鈕點擊事件處理
Sub DataCleaningMacro(control As IRibbonControl)MsgBox "執行數據清洗操作", vbInformation' 實際功能代碼
End SubSub MergeSheetsMacro(control As IRibbonControl)MsgBox "執行工作表合并", vbInformation
End Sub
步驟4:驗證與調試
通過Custom UI Editor工具直接注入XML(推薦)
使用IRibbonUI.Invalidate方法刷新界面:
Dim MyRibbon As IRibbonUISub ribbonLoaded(ribbon As IRibbonUI)Set MyRibbon = ribbon
End SubSub RefreshRibbon()MyRibbon.Invalidate
End Sub
二、示例1 總結
這個示例過于復雜,而且卡在第四步,我覺得應該尋找更好、更簡單的辦法。
三、示例2 創建VSTO外接程序
步驟1:新建解決方案和Excel VSTO 外接程序項目
創建一個Excel VSTO外接程序的新項目,選擇“Excel VSTO外接程序(Visual Basic)”模板,命名為“外接程序安裝”。VS將顯示解決方案名稱為“外接程序安裝”,包含“外接程序安裝”項目。
步驟2:設計Excel VSTO外接程序
主要是設計菜單項和代碼。
1.在“外接程序安裝”項目上,點擊右鍵,選擇“添加”——“類”,在“添加新項-外接程序安裝”界面,選擇“office/sharepoint”中的“功能區(可視化設計器)”,點擊“添加”后默認建立“Ribbon1.vb”的模塊。
2.依次右鍵點擊“Group1”、“TabAddins(內置)”,均選擇“ 刪除”。
(1)點擊左側的“工具箱”,拖拽“Office 功能區控件”中的Tab按鈕到“Ribbon1.vb[設計]”中,修改右側屬性的有關值,如Label改為“關于”等。
(2)再次點擊左側的“工具箱”,拖拽“Office 功能區控件”中的Group按鈕到“Ribbon1.vb[設計]”的“關于”里面,修改右側屬性的有關值,如Label改為“幫助”等。
(3)點擊左側的“工具箱”,拖拽“Office 功能區控件”中的Group按鈕到“Ribbon1.vb[設計]”中的幫助里面,修改右側屬性的有關值,如Label改為“版本”,ControlSize改為“RibbonControlSizeLarge”,OfficeImageId改為“Help”等。
3.雙擊“版本”圖標,進入“Ribbon1.vb”的代碼編輯界面,在Button1_Click的過程中,輸入以下代碼
MsgBox(“version 1.0.0.0”)
引用資料: 創建 VSTO 外接程序的windows安裝包
https://blog.csdn.net/weixin_45661908/article/details/123310069
三、示例2 總結
跟著做了一遍,在第二條:MsgBox(“version 1.0.0.0”) 這里卡住了。
思路了半天,反應過來,他是用的VB,而我用的C#。 尷尬了
嗯 最終跟著做完,挺詳細、簡單的,安裝那部分不用過分深入,了解就行。主要是熟悉外接程序的搭建。
四、示例 3 C# VSTO外接程序示例
步驟1:創建一個Excel外接程序:
步驟2:添加項,添加一個Ribbon菜單:
步驟3 : 熟悉Tab控件
RibbonTab控件是所有控件的容器
步驟4: 熟悉Group控件
Group控件的作用是將我們的功能進行分組。回到我們之前的規劃,我們的歪歪插件有財經,地圖,天氣,關于這幾大功能。所以我們需要在界面上放置4個Group控件,并對其進行命名。
步驟5 :Menu控件和SpliterButton控件
在分好類之后,我們需要對每個分類的細小功能進行設計,這里面我們需要放置各種控件,首先我們可能會接觸到的就是Menu控件,里面可以包含Button,SplitButton等。
步驟6:RibbonXml
在Office中Ribbon菜單時可以通過RibbonXML進行配置,也就是說,上面的可視化界面設計其實是為我們提供了編輯RibbonXML的設計時支持。其實我們也可以直接創建一個XML文件進行設計,然后在代碼中進行加載,同樣能夠實現這樣的功能。在有些情況下,比如我們創建SharedAddin程序時,根本沒有設計時支持。所以了解RibbonXML對于創建可兼容多版本Excel菜單系統顯得尤為重要。
要創建RibbonXML最好的做法是對著新建的可視化菜單,然后右鍵->將功能區導出到XML。然后項目會自動創建Ribbon.xml和Ribbon.cs文件,其中Ribbon.xml是布局文件,Ribbon.cs是事件處理代碼。
打開Ribbon.xml可以看到如下代碼,可以看到這個UI界面的展現即是使用了該XML文件來進行渲染的,其中在XML中還可以聲明一些事件,后面會講。
現在,如何在我們的應用程序中加載該RibbonXML并渲染出Ribbon菜單呢?首先,我們將之前的添加的可視化設計的Ribbon菜單YYMenu.cs排除到項目外。然后轉到ThisAddIn.cs中,覆寫Office.IRibbonExtensibility 接口的CreateRibbonExtensibilityObject方法,實例化自動生成的Ribbon類,然后返回。
//ThisAddIn.cs
private Ribbon customerRibbon;protected override Office.IRibbonExtensibility CreateRibbonExtensibilityObject()
{customerRibbon = new Ribbon();return customerRibbon;
}
運行程序,即可看到如下效果:
可以看到圖片不見了,這是因為在導出功能區為XML的時候,VS沒有幫我們處理圖片,所以需要我們自己來添加。在RibbonXML文檔中, customUI節點下有loadImage事件,Button有getImage事件和image屬性。customUI節點的loadImage方法和子節點的image屬性一起使用,image屬性作為loadImage方法的參數。
loadImage方法如下:
//Ribbon.cs
public Image LoadImage(string imageName)
{Assembly assembly = Assembly.GetExecutingAssembly();//String[] all =assembly.GetManifestResourceNames();//GetResourceNameStream stream = assembly.GetManifestResourceStream("YYAddIn.Resources." + imageName);return Image.FromStream(stream);
}
其中,imageName即為Button控件的image屬性要設置的圖片名稱。資源文件圖片,要設置為嵌入的資源。
引用資料: 淺談Excel開發:二 Excel 菜單系統
https://blog.csdn.net/dyllove98/article/details/9707613
四、示例 3 總結
示例3是最符合我需求的測試,它為我初衷‘便捷的調用VBA 創造了可能’。當然也遇到一些問題。
問題1:老是被EXCEL 的加載項禁用,需要手動解除。不然就尷尬了
問題2:步驟6,圖片出不來,忘記設置本地資源屬性設置造成的。
五、實現C# 的VSTO調用VBA函數(xlam)
C#調用VBA(xlam)的代碼我會放文末。不管作用大小,好歹是個思路。主要代碼如下。
步驟1:添加一個測試項目 test2,做界面就是group里加個button,然后生成XML
步驟2:我的測試界面生成的XML
<?xml version="1.0" encoding="UTF-8"?>
<customUI onLoad="Ribbon_Load" xmlns="http://schemas.microsoft.com/office/2006/01/customui" loadImage="LoadImage"><ribbon><tabs><tab id="tab1" label="mytest2"><group id="group1" label="group1"><button id="button1" label="button1" size="large" image="exlLogo.jpg" onAction="testdo1" /></group></tab></tabs></ribbon>
</customUI>
XML 中加入LoadImage、testdo1 ,LoadImage加載圖片、testdo1是我想調用的xlam函數。
步驟3: 項目中排除界面文件Ribbon1.cs,
ThisAddIn.cs 中添加 啟用XML生成
private Ribbon customerRibbon;protected override Office.IRibbonExtensibility CreateRibbonExtensibilityObject()
{customerRibbon = new Ribbon();return customerRibbon;
}
步驟4:Ribbon.cs寫入 本地圖片加載
public Image LoadImage(string imageName) {Assembly assembly = Assembly.GetExecutingAssembly();//String[] all = assembly.GetManifestResourceNames();//GetResourceName//return null;Stream stream = assembly.GetManifestResourceStream("test2.Resources." + imageName);return Image.FromStream(stream);}
步驟5:建一個測試VBA 函數 并保存為 ‘我的測試.xlam’
不需要添加到excel加載項,因為這樣外接程序也讀取不到,我測試過了。
步驟6:修改按鈕事件響應
將Ribbon.cs 的 GetCustomUI 用下面代碼覆蓋掉
Microsoft.Office.Interop.Excel.Application excelApp = null;public string GetCustomUI(string ribbonID){excelApp = Globals.ThisAddIn.Application;// 加載xlam文件(若未自動加載)excelApp.Workbooks.Open(@"C:\Users\cs\Desktop\我的測試.xlam", ReadOnly: true);return GetResourceText("test2.Ribbon.xml");}public void testdo1(Office.IRibbonControl control){excelApp.Run("我的測試.xlam!模塊1.testdo1");/*// 方式2:傳遞參數調用object arg1 = "參數1";object arg2 = 100;excelApp.Run("MyMacro.xlam!Module1.ProcessData", arg1, arg2);// 方式3:使用動態類型(需引用Microsoft.CSharp)dynamic excel = excelApp;excel.Run("MyMacro.xlam!Module1.AdvancedCalc", 15.5, DateTime.Now);*//* try{if (control.Id.Equals("btntest")){}}catch (COMException ex){Console.WriteLine("Create CTP encounter errors: " + ex.ToString());}*/}
運行效果:
六、結語
1、最終,貼一下本文的測試代碼下載
C# 的VSTO調用VBA函數(xlam)示例代碼
https://download.csdn.net/download/yqsy123123/90724022
我也不知道直接更新覆蓋VBA的文件夾、和寫一個自動更新的程序哪個更復雜,主要是想到了看能不能實現,還是挺有意思的
2、至于,寫好的VSTO如何注入EXCEL,那就得參考示例2 的安裝部分了。
創建 VSTO 外接程序的windows安裝包
https://blog.csdn.net/weixin_45661908/article/details/123310069
3、標記一個EXCEL內置圖標的,
兼容Office和WPS中Word圖標庫
https://blog.csdn.net/weixin_45055317/article/details/133832128
你們有可以預覽的圖標庫地址,分享一個,萬分感謝。
再次感謝本文引用資源的作者。