国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
RibbonX API: 利用您自己的功能區(qū)選項卡和控件擴展 2007 Office Sy...
利用您自己的功能區(qū)選項卡和控件擴展 2007 Office System
Eric Faller

本文討論:
  • 功能區(qū)簡介
  • RibbonX 控件和功能
  • 升級加載項以使用 RibbonX
  • 為 Word 和 Excel 構建加載項
本文使用了以下技術:
2007 Microsoft Office 系統(tǒng)
下載本文中所用的代碼: RibbonX2007_02.exe (201 KB)
瀏覽在線代碼
如果您曾見過 2007 Microsoft Office 系統(tǒng),那么您會發(fā)現(xiàn)新的 Microsoft? Office 用戶界面與以前的 Office 版本有著本質的區(qū)別。因此,當您了解到 UI 背后的可擴展性模型也為全新時,應該也不會感到吃驚了。
與其擴展的舊工具欄和菜單非常類似,CommandBars 對象模型(從 Office 97 開始提供)難以有效地使用。新模型被稱為 RibbonX,它具有許多與新 UI 本身相同的屬性:易于使用、一致性、時尚性和可預見性(對最終用戶而言)。
通過使用 XML 來指定 UI 的內容和結構并在其背后使用動態(tài)回調機制,RibbonX 將 UI 設計從其背后的代碼中解脫出來。稍后我將在本文中說明所有相關細節(jié),但在這之前,我會先介紹經(jīng)驗豐富的 Office 開發(fā)人員可能感興趣的一些有關新 UI 的內容。
在拋棄舊 UI 的同時,Microsoft 也舍棄了許多熟悉的術語并使用陌生的新概念來代替它們。我們先來看看新 UI 的基礎知識,確保所有人都能對它有基本了解。圖 1 顯示的 Microsoft Office Word 2007 上標出了每個主要 UI 組件。
圖 1 新 Word 2007 界面的元素 (單擊該圖像獲得較大視圖)
1. 功能區(qū) 文檔上方的大矩形區(qū)域即是功能區(qū)。它包含標題欄、Office 按鈕、快速訪問工具欄及選項卡。RibbonX 主要應用于功能區(qū)及其內部的每一項。
2. Office 按鈕 此按鈕會顯示 Office 菜單,該菜單與 Office 先前版本中的“文件”菜單大致相同。Office 菜單包含多個命令,這些命令是對文檔進行操作,而不是對文檔的內容進行操作。使用 RibbonX 加載項可以隨意改變 Office 菜單的內容(但是它們不能自定義 Office 按鈕本身)。
3. 快速訪問工具欄 此工具欄包含常用的命令,而且是最終用戶進行自定義的主要位置。用戶可以右鍵單擊任何功能區(qū)控件并將其添加到快速訪問工具欄(包括自定義 RibbonX 控件)。因為它的設計目的便是作為一塊“屬于”最終用戶的空間,所以通常不允許 RibbonX 加載項改變快速訪問工具欄,除非它們已經(jīng)啟用 StartFromScratch 模式。
4. 選項卡 選項卡是構成功能區(qū)的主要內容,而且包含用于處理文檔內容的 UI 控件。RibbonX 加載項可以創(chuàng)建它們自己的自定義選項卡,并改變內置選項卡的可見性和標簽。
5. 上下文選項卡集 選中文檔內部的對象(例如圖片或表)時,即會出現(xiàn)上下文選項卡集,其中包含所有用于處理這些對象的 UI 元素。RibbonX 加載項可以改變內置選項卡集的可見性,并向其添加自定義選項卡。2007 Office 版本不支持創(chuàng)建自定義上下文選項卡集。選項卡集包含上下文選項卡,它們的作用方式與常規(guī)選項卡相同。
6. 組 選項卡包含組的集合,組中則包含各個 UI 控件。RibbonX 加載項可以改變內置組的可見性,并創(chuàng)建它們自己的自定義組。但它們不能改變內置組的內容。此限制可以保護 UI 布局并防止加載項之間相互沖突以及加載項與 Office 的將來版本發(fā)生沖突。根據(jù)選擇,組的角落處可擁有對話框啟動器,用于顯示與組相關的對話框(例如“字體”或“段落”對話框)。
7. 任務窗格 2007 Office 系統(tǒng)中仍存在若干任務窗格,而且現(xiàn)在支持同時打開多個任務窗格。COM 加載項現(xiàn)在可以創(chuàng)建托管 ActiveX? 控件或 Windows? 窗體控件等內容的 CustomTaskPane。(CustomTaskPane 功能與 RibbonX 不同,但本文不會對此進行介紹。)
8. MiniToolbar MiniToolbar 是選定文本和右鍵單擊上下文菜單時出現(xiàn)的常見格式命令集合。RibbonX 加載項不能修改 MiniToolbar 的內容,但它們可以禁用或重用其內置命令。
9. 上下文菜單 這些上下文菜單與 Office 先前版本中我們熟悉和喜愛的那些上下文菜單相同。在 2007 Office 版本中,RibbonX 不應用于上下文菜單,但使用 CommandBars 對象模型可以像過去那樣擴展和自定義它們。
10. 狀態(tài)欄 狀態(tài)欄包含幾個方便的新控件,如字數(shù)統(tǒng)計和視圖滑塊。盡管狀態(tài)欄可以隱藏,但在 2007 Office 系統(tǒng)中加載項不可以自定義狀態(tài)欄。

對現(xiàn)有加載項的支持
如果您已針對 Office 2003 編寫了加載項,您可能想知道它們在 2007 版本中是否仍起作用。很高興,答案是肯定的,它們仍可以很好地運行(除非它們做些不可思議的事情,如檢查 Office 版本并拒絕在新版本上運行)。所有的舊菜單和工具欄仍存在于表面之下,原因很簡單,因為操控它們的舊式加載項仍需要在 2007 Office 系統(tǒng)上運行。它們在新 UI 中如何顯示?讓我們看一個示例。
圖 2 顯示了一個假定的 Word 2003 加載項(該加載項創(chuàng)建一個自定義工具欄并將幾個按鈕添加到舊菜單和工具欄)以及在 Word 2007 中進行加載時該加載項的外觀。
圖 2a Word 2003 和 Word 2007 中的同一加載項 
圖 2b
如您所見,當加載舊式 CommandBar 加載項時,“加載項”選項卡顯示在功能區(qū)內。“加載項”選項卡包含三個組:“菜單命令”、“工具欄命令”和“自定義工具欄”?!安藛蚊睢焙汀肮ぞ邫诿睢苯M分別包含添加到舊式內置菜單和工具欄中的自定義控件。它們還顯示由加載項重用以執(zhí)行自定義操作(通過設置 OnAction 或 Hyperlink 屬性)的任何舊式內置控件。“自定義工具欄”組將任何舊式自定義工具欄顯示為水平區(qū)域??丶墓ぞ咛崾緯@示控件所在的舊式工具欄的名稱。
如果在卸載后某個行為異常的加載項留在了按鈕背后,用戶可以右鍵單擊“加載項”選項卡中的控件,然后將它們從舊式 CommandBar 結構中刪除。

RibbonX 中的新功能
RibbonX 使 Office 編程進入基于 XML 的 UI 聲明的現(xiàn)代化時代。您現(xiàn)在可以在結構化標記窗體中創(chuàng)建指定 UI 外觀的 XML 文件,而不再需要使用一系列對象模型調用來編寫構建 UI 的復雜代碼。這對于加載項編寫者而言有許多好處。
首先,您可以將 UI 與代碼分離。UI 設計者不需要為了嘗試新設計而知道手動更新代碼的方法。事實上,如果加載項選擇從外部文件加載其 XML,那么甚至可以不必重新編譯該加載項即可修改和完善 UI。這便消除了硬編碼 UI 系統(tǒng)所需的反復“編輯”、“編譯”、“運行”循環(huán)的中間步驟。
其次,Office 能分辨加載項的完整 UI。這一點看上去似乎并不重要。但是,如果您知道使用 CommandBars 時,Office 的先前版本不知道哪些工具欄和菜單屬于哪個加載項,而且所有的 UI 修改都通過 COM 調用來實現(xiàn),而這些調用不可追溯回到任何個別加載項,那么您就能明白它的重要性。Office 之前版本的這個特點會導致一些煩人的問題,而現(xiàn)在這些問題完全可以避免。
第三,Office 可以自動清理加載項的 UI。以前,加載項必須使用特殊代碼在關閉或卸載時檢查其菜單和工具欄并將它們刪除。如果加載項崩潰或不能正確地進行自身清理(此情況曾多次發(fā)生),它會將無用的按鈕留在 UI 中。由于 2007 Office 系統(tǒng)可以自動清理加載項 UI,因此不必寫入任何清理代碼,也不會有殘留的 UI。
不同 Office 版本之間的差別是您需避免的另一個問題。有效的 XML 文件需要包含 xmlns 命名空間聲明,用于標識文件所遵循的架構版本。這樣,RibbonX 便能得知特定加載項所針對的 Office 版本,并能在版本之間有差異時正確映射 UI。CommandBars 對象模型缺少版本控制和所有權是造成以下情況的兩個主要原因:更新到新版本 Office 時舊式加載項常常遭到破壞;“加載項”選項卡無法很好地區(qū)分由 OM 調用添加到其中的雜亂控件。
最后,XML 具有良好的工具支持。只需通過拖放,便能利用所提供的 RibbonX 架構定義文件 (XSD)、各種 XML 編輯器(包括 Word 2007 本身)創(chuàng)建有效的 RibbonX UI 文件。
CommandBars 對象模型可視為使用“推”模型,其中加載項會通過設置對象模型中的各種屬性將所有 UI 數(shù)據(jù)推入 Office。UI 中控件的每個屬性必須在啟動時由加載項明確設置,即使此控件所在的菜單或工具欄從未顯示。如果這涉及加載大量圖像文件,則會對性能造成極大影響。
RibbonX 使用“拉”模型,其中 Office 僅在需要時將數(shù)據(jù)從加載項中拉出。加載項提供 get 回調,例如 getLabel 或 getImage,而不再設置像 CommandBar.Name 或 CommandBarButton.Picture 之類的屬性。需要知道某個控件的標簽或圖像時,Office 便會調用這些回調。
拉模型的主要優(yōu)點在于性能優(yōu)勢。在 2007 Office 版本中,應用程序啟動時可能大多數(shù)加載項的 UI 都不可見,尤其是當加載項在“加載項”選項卡中添加了自己的頂級選項卡或組時。因此沒有必要立即加載這些控件的所有圖像,否則會導致性能急劇下降。僅需在用戶單擊該選項卡時加載圖像。RibbonX 會盡可能延遲回調的調用,以分攤整個會話中的資源加載成本,并在即便安裝了若干加載項的情況下保持 Office 應用程序快速啟動。
如果 Office 確定調用這些回調的時間,您可能想知道如何動態(tài)更改控件屬性。RibbonX 緩存回調的返回值,并且在加載項使這些返回值無效之前不會進行回調。加載項可以通過 IRibbonUI 接口的 Invalidate 和 InvalidateControl 方法來實現(xiàn)此目的。一旦控件的屬性失效,RibbonX 即會知道在下次需要時進行回調。如果此控件當前顯示在屏幕上,它將立即回調并更新值。如果它沒有顯示在屏幕上,則 RibbonX 會等到它出現(xiàn)在屏幕上時才進行回調。下面我們將深入探討實現(xiàn)回調功能的所有細節(jié),并在文中的示例加載項中詳細介紹如何進行失效。
RibbonX 提供許多不同的控件類型以用于擴展,包括圖 3 中所示的這些控件類型。CommandBars 只能使用此列表中的前六項,但現(xiàn)在有許多新 UI 選項可供 RibbonX 加載項使用。其中,最引人注目的新控件類型應是包括按鈕和下拉菜單的 splitButton(請參見圖 4)以及展開以顯示圖像選擇的庫。兩者均廣泛應用于 2007 Office 版本中,目的是減少 UI 混亂并方便預覽可見操作。我們也鼓勵加載項編寫者使用這些新控件類型來為自己的 UI 提供相同的效果。

RibbonX 控件
1. 按鈕
2. toggleButton
3. editBox
4. 菜單
5. comboBox
6. dropDown
7. dialogBoxLauncher
8. 庫
9. splitButton
10. 標簽
11. checkBox
12. 組
13. 選項卡
14. superTip
圖 4 SplitButton 

StartFromScratch 模式
許多開發(fā)人員使用 Office 作為平臺來構建自己的自我包含應用程序。運行時,這些應用程序通常會刪除所有的內置 Office UI 并使用自己的 UI 進行替換。因為不存在使用 CommandBars 執(zhí)行此操作的標準機制,因此實施過程中總是充滿了困難和錯誤。
RibbonX 引入了 StartFromScratch 模式,從而使隱藏 Office UI 與編寫一行 XML 一樣容易。在啟動 <ribbon> 標記上設置 startFromScratch="true",將執(zhí)行以下操作:
  • 隱藏所有的主要頂級內置選項卡(但不包括上下文選項卡集)
  • 隱藏快速訪問工具欄的內容
  • 允許加載項將自己的按鈕添加到快速訪問工具欄(這通常是受到禁止的)
  • 隱藏 Office 菜單上除“新建”、“打開”和“保存”以外的所有命令
一旦應用這些更改,加載項可以進一步更改 UI,包括顯示某些內置選項卡或隱藏更多的選項卡集或 Office 菜單項。
通過手動隱藏所有這些 UI 元素可以執(zhí)行 StartFromScratch 模式的大多數(shù)功能,但與手動執(zhí)行此操作相比,StartFromScratch 具有明顯優(yōu)勢。首先,編寫一行 XML 代碼比寫五十行要容易多了。其次,它的設計向前兼容將來的 Office 版本。如果 Word 的新版本添加了新的頂級選項卡或 Office 菜單項,StartFromScratch 模式會自動隱藏它們,但手動隱藏 UI 的加載項則需要更新才能隱藏這些新元素。
StartFromScratch 模式的另一個重要功能是它基于每個文檔工作。如果用戶在多文檔界面 (MDI) 模式下編輯多個文檔,文檔之一啟用了 StartFromScratch 模式,那么用戶在該文檔與其他文檔之間切換時,所有 UI 都將自動隱藏或顯示。不需要任何代碼!

命令禁用和重用
Office 加載項的另一個常見用途是禁用內置命令。RibbonX 仍可使此操作與編寫一行代碼一樣容易。開發(fā)人員可以使用與 XML 的 <commands> 部分中內容類似的行來禁用內置命令:
<command idMso="Bold" enabled="false"/> 
這將禁用在 UI 任何位置出現(xiàn)的“Bold”(粗體)按鈕(默認配置下,UI 的功能區(qū)及 MiniToolbar 都包括“Font”(字體)組)。
因為使用 CommandBars 不會發(fā)生此情況,所以務必要注意此操作會禁用兩個位置中的“Bold”(粗體)按鈕。當用戶自定義了工具欄并將副本放置在其他位置時,加載項需要從頭至尾檢查整個 UI 并手動禁用該按鈕的每個副本。它們還必須按其 ID 號(例如 43 或其他數(shù)字)來搜索命令,而不是按用戶易理解的名稱(如“Bold”)進行搜索。如果加載項想在某些時刻有條件地禁用命令,則還可以使用 getEnabled 回調。
<commands> XML 元素也是 RibbonX 命令重用功能的始發(fā)區(qū)域。加載項通常會增強或擴展 Office 的內置功能、接管現(xiàn)有的 UI 按鈕并重用它們。另外,IT 管理員有時還選擇使用重用來限制功能(例如,單擊“打印”按鈕時顯示密碼對話框)。
可以使用 RibbonX 來重用在單擊時執(zhí)行操作的任何按鈕(但不能重用較復雜的控件類型,例如庫或組合框)。下面是重用“Save”(保存)按鈕所需的 XML 的示例:
<command idMso="Save" onAction="MySaveFunction"/>
當單擊“Save”(保存)時,加載項的 MySaveFunction 將運行,從而為加載項提供執(zhí)行其自己的操作的機會,并可選擇是否允許內置 Save 函數(shù)執(zhí)行。
再次,Save 按鈕的所有副本(位于 Office 菜單和快速訪問工具欄上)將由此行 XML 重用,并且如果個別文檔正在執(zhí)行重用,則此操作不會應用于其他打開的文檔(除非該文檔被加載為全局模板或加載項)。

按需加載
使用 Office 加載項的一個問題是其 DLL 經(jīng)常需要一段時間才能啟動,尤其是在它們都以托管代碼編寫且公共語言運行庫 (CLR) 還未加載時。安裝了若干加載項的用戶會在每次啟動 Office 應用程序時察覺到嚴重的性能問題。具有諷刺意味的是,用戶可能根本不會在任何特定會話中用到其中的大多數(shù)加載項,但他們卻需要在所有操作中付出代價。
由于低速會對 Office 和加載項產生負面影響,因此 Office 為 COM 加載項提供了稱為按需加載的功能。此功能在 2007 Office 版本中已進行了升級,并被擴展以包括 RibbonX 支持。其過程的概述如下。加載項編寫者將加載項的 LoadBehavior 注冊表項設置為 ConnectFirstTime (16)。安裝加載項后第一次啟動應用程序時,即會啟動加載項。Office 在加載項中查詢其 RibbonX XML 并將它緩存在磁盤上。RibbonX 然后調用加載項的所有 Get 回調,以便加載其所有圖像并緩存加載項的初始狀態(tài)。
關閉時,加載項的注冊表項將更改為 DemandLoad。在應用程序的后續(xù)啟動中,加載項將不啟動,但會顯示其 RibbonX UI,就像已加載了一樣。用戶只要一單擊加載項的按鈕之一,即會載入加載項以執(zhí)行用戶的命令。
按需加載對最終用戶而言是透明的,除了設置注冊表項外,開發(fā)人員不需要進行任何其他工作。(您可將此與使用 CommandBars 通過設置 <!ProgID> 字符串來使用按需加載的麻煩程度相比較。)顯然,按需加載并非對每個加載項都適用,但對于只將單個按鈕或菜單項添加到 UI 然后在單擊所添加項時激活其功能的大多數(shù)加載項而言,它相當有用。然而,需要在用戶與其 UI 交互之前運行復雜代碼的較復雜加載項無法使用按需加載,因為它們需要進行加載以運行代碼。

將 Word 模板升級到 RibbonX
剛才我們已介紹了 RibbonX 的所有主要功能,現(xiàn)在讓我們用一些示例加載項和代碼段來做進一步的深入研究。首先,讓我們看看許多開發(fā)人員在切換到 2007 Office 系統(tǒng)時將會遇到的情況:將舊式加載項從 CommandBars 升級到 RibbonX。
我要升級的加載項是相當簡單的 Word 模板 (.dot),該模板用于將空白頁插入法律文檔,并將標準(且自相矛盾)的“This page intentionally left blank”(本頁故意留為空白)文本填入該頁面。
使用文檔附加的 CommandBars 中“Insert”(插入)菜單上的按鈕來實現(xiàn)該加載項。按鈕的 OnAction 屬性被設置為 InsertBlankPage,這是包含以下代碼的 Visual Basic? for Applications (VBA) 宏:
Sub InsertBlankPage()    ' 插入一個空白頁面    Selection.InsertBreak Type:=wdPageBreak    Selection.ParagraphFormat.Alignment = wdAlignParagraphCenter    Selection.Font.Size = 14    Selection.Font.Color = wdColorGray50    Selection.Font.Name = "Arial Black"    Selection.TypeText Text:="有意將此頁面留為空白"    Selection.InsertBreak Type:=wdPageBreakEnd Sub
顯然它并不非常復雜,因為這只是一個演示版。此文件可以從 MSDN? 雜志網(wǎng)站下載。您可以使用“Templates”(模板)和“Add-Ins”(加載項)對話框將它安裝為全局模板。
將舊式 CommandBar 加載項升級到新 2007 Office 系統(tǒng) UI 的第一步是將舊 UI 映射到新模型中。由于功能區(qū)會取代所有的工具欄和菜單,要立即找到最適合加載項 UI 的位置并不容易。
因此在要進行此操作之前,先停下來考慮一下并問您自己“我們真的需要升級此加載項嗎?”在多數(shù)情況下,如果預算緊張,答案可能是“不需要”。如果您在 Word 2007 中加載該加載項,那么它可以在“Add-Ins”(加載項)選項卡中正常工作(請參見圖 5)。
圖 5 舊式加載項 
它在該處的工作并沒有特別不對勁的地方,但您可能不喜歡它與所有其他的舊式加載項都保留在“Menu Commands”(菜單命令)組中,而且它不使用 RibbonX 的任何新功能。它也不是一個優(yōu)秀的示范,我們不能就此結束,所以讓我們繼續(xù)。
由于該加載項將頁插入到文檔中,因此 UI 可能最好位于“Insert”(插入)選項卡上。如果該加載項將文檔作為一個整體進行操控,則可選擇將其 UI 放置在 Office 菜單中。如果在現(xiàn)有 UI 中沒有適合它的位置,則“Add-Ins”(加載項)選項卡上的自定義組是一個不錯的選擇(避免創(chuàng)建只有一個按鈕的選項卡)。
Word 的內置“Insert”(插入)選項卡包含一個用于插入頁的組,而且它已經(jīng)包含一個用于插入空白頁的按鈕(2007 Office 版本的一個新功能)。由于舊式加載項還會插入“Intentionally Blank”(故意留為空白)占位文本,我希望將其與內置功能區(qū)分開。讓我們將一個名為“Legal Pages”(法律頁)的自定義組插入到另一個組的旁邊,而且添加一個具有指示性圖標的大按鈕。圖 6 顯示了其完成時的外觀。
圖 6 插入頁加載項 
下一步是拿出生成所需結果的 XML 文件。在演示中,先給出最終產品再解釋其工作方式通常是最快速直觀的方法。本著此精神,我們在圖 7 中給出了最終的 XML。
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">  <ribbon>    <tabs>      <tab idMso="TabInsert">        <group id="LegalGroup" label="法律條文頁面"                insertAfterMso="GroupInsertPages">          <button id="BlankPageButton" label="有意留為空白頁面"                  size="large" image="BlankIcon"/>    </group>   </tab>  </tabs> </ribbon></customUI>
如您所見,它相當簡單。根標記為 <customUI> 并指定 2007 Office 系統(tǒng) RibbonX XML 命名空間開始。然后,仔細檢查反映 UI 結構的一系列標記:Ribbon > Tabs > Tab > Group > Button。
第一個有趣的項是 <tab> 標記上的 idMso="TabInsert" 屬性。XML 中的所有控件都必須具有 ID 屬性以標識它們。內置控件使用 idMso 以顯示它們是 Office 控件并將它們與使用 id 屬性的自定義控件區(qū)分。因此,XML 文件實際上是在表示“查找內置‘Insert’(插入)選項卡并在其內部創(chuàng)建自定義組”。insertAfterMso="GroupInsertPages" 屬性表示“將此組插入內置‘Pages’(頁)組之后”。最后,按鈕 id="BlankPageButton" 表示“在組內部創(chuàng)建一個自定義按鈕”。
在此示例中,組和按鈕的標簽是在 XML 中靜態(tài)指定的,因此它們永遠不會更改。在本例中這樣沒有問題,但如果您希望動態(tài)更改標簽(可能出于本地化目的),您可以改用 getLabel 屬性來指定要返回標簽的函數(shù)。
最后一個有趣的部分是 image="BlankIcon" 屬性。它指示 RibbonX 在 Word 模板文件中搜索具有該 ID 的圖像。在插入 XML 的同時您需要將該圖像粘貼在該文件中。

添加 XML 和圖像
僅 2007 Office 版本的新文件格式支持附加的 RibbonX XML,因此您需要做的第一件事就是打開 .dot 文件,然后將其另存為 .dotm 文件(添加的“m”意味著文件具有宏)。接下來,使用 .zip 擴展名重命名文件并將其打開以檢查內容,如圖 8 所示。
圖 8 文檔模板內部 (單擊該圖像獲得較大視圖)
Open XML 文件格式會在另一篇文章中詳細介紹,在此處我們可以將它簡單概括為:包含以各種方式彼此相關的一批文件的壓縮包。在此示例中,document.xml 是主 Word 文檔,它與樣式信息、VBA 代碼以及附加的 CommandBars 等各種內容相關。由于我不想再讓文件具有附加的 CommandBars,因此我們將 attachedToolbars.bin 文件從 .zip 文件中刪除,然后再重新打包。
我們可以手動編輯 .zip 文件以插入 RibbonX XML 和圖標圖像,但用工具來執(zhí)行此操作會容易得多,所以我們選擇使用工具。在 openxmldeveloper.org 上,有一大堆可用來處理 Open XML 文件格式的工具。您所需要的是名為 Custom UI Editor 的工具。
Custom UI Editor 是一款方便小巧的工具,可用來將 RibbonX XML 和相關聯(lián)的圖像插入到 Open XML 格式文件中。使用它打開 .dotm 文件,然后粘貼到 XML 中并插入圖像(請參見圖 9)。保存文件。如果您很好奇,您可以將它作為 .zip 文件打開,然后會看到該工具分別在創(chuàng)建了 XML 文件 \customUI\customUI.xml 和圖像 \customUI\images\BlankIcon.png。它還修改了幾個 rels 關系以指向這些新文件。
圖 9 編輯模板 (單擊該圖像獲得較大視圖)
如果您在 Word 中打開該文件,現(xiàn)在您將看到新按鈕,但在單擊時它不執(zhí)行任何操作。這是顯而易見的,因為您還未告訴它要調用哪個宏。要執(zhí)行此操作,將此處以紅色顯示的屬性添加到 XML:
<button id="BlankPageButton" label="有意留為空白頁面"         size="large" image="BlankIcon"        onAction="RibbonXOnAction" tag="InsertBlankPage" />
剛開始,您可能會感到奇怪,不明白為什么引入一個名為 RibbonXOnAction 的新宏,而不是重用 InsertBlankPage 宏。我這樣做的原因是 RibbonX OnAction 宏所具有的簽名與其 CommandBar 對應部分的簽名不同。如果您有許多宏,則您需完全手動來更改它們,這既費時又易產生錯誤。而且它會破壞代碼,從而無法在 Office 的先前版本上運行。
通過使新 RibbonX 宏調用舊 CommandBar 宏,則可以避免這兩個問題。此時,引入標記屬性:它是不在 UI 中使用的字符串屬性,但其被傳遞到加載項的代碼以供在那里使用。以下是在 RibbonXOnAction 宏中使用它的方式,您可以將下列代碼粘貼到新 VBA 模塊中:
Sub RibbonXOnAction(button As IRibbonControl)    Application.Run button.TagEnd Sub
RibbonX OnAction 宏采用 IRibbonControl 對象作為參數(shù),代表被單擊的按鈕。在 CommandBars 中,OnAction 宏沒有參數(shù),因此要指出被單擊的按鈕有時會顯得比較困難。IRibbonControl 對象提供 ID 和 Tag 屬性以解決 RibbonX 中的此問題。
將此宏放置在適當?shù)奈恢煤?,特別的新按鈕即會開始工作!這就是使用 RibbonX 來升級此加載項的代碼以運行而要做的全部工作:一個新的單行宏,且不對現(xiàn)有代碼進行任何更改。太精彩了。

Excel 的 COM 加載項
在第二個示例中,我們將執(zhí)行一些稍微復雜的工作并為 Excel? 編寫一個 COM 加載項。該加載項是一個小型的業(yè)務線 (LOB) 應用程序,用于填寫和提交時間卡片。限于篇幅,我僅在此處提供部分代碼,完整源代碼可在代碼下載中找到。
第一步仍是指出所需要的 UI 種類。該加載項允許用戶創(chuàng)建時間卡片,然后編輯并提交它們。因為剛開始需要顯示的時間卡片 UI 只有“New Timecard”(新建時間卡片)按鈕,因此請將其放置在 Office 菜單上(請參見圖 10)。
圖 10 新按鈕 
單擊“New Timecard”(新建時間卡片)按鈕后(或打開現(xiàn)有時間卡片后),即會在自定義選項卡中顯示其余時間卡片 UI。由于“Page Layout”(頁面布局)、“Formulas”(公式)、“Review”(審閱)和“Data”(數(shù)據(jù))等各種 Excel 選項卡不能應用于填寫時間卡片,請同時隱藏這些選項卡(請參見圖 11)。
圖 11 自定義時間卡片功能區(qū)選項卡 (單擊該圖像獲得較大視圖)
時間卡片 UI 明顯比先前的加載項 UI 復雜得多,而創(chuàng)建它的是 XML,如圖 12 中所示。COM 加載項需要使用 RibbonX 做的第一件事就是實現(xiàn) IRibbonExtensibility 界面。幸運的是,Visual Studio? IntelliSense? 功能可以輕松地實現(xiàn)這一點。創(chuàng)建一個加載項,方法是選擇 Visual Studio 中的“新建項目”,轉到“其他項目類型”類別,然后選擇“擴展性”部分中的“共享的外接程序”。
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui"          onLoad="OnLoad" loadImage="LoadImage">  <ribbon>    <officeMenu>      <button id="NewTimecard" insertAfterMso="FileNew"               label="新建時間卡片" imageMso="StartAfterPrevious"              onAction="NewTimecard" />    </officeMenu>    <tabs>      <tab id="TimecardTab" label="Timecard"           getVisible="IsCustomTabVisible">        <group id="EditingTools" label="編輯工具">          <button id="ClearTimecard" label="清除時間卡片" size="large"                   imageMso="TableDeleteRowsAndColumnsMenuWord"                  onAction="ClearTimecard"/>          <button id="InsertDay" label="插入新的一天" size="large"                  imageMso="CellsInsertDialog" onAction="InsertNewDay"/>          <button id="CalculateTotal" label="計算工作時間"                   size="large" imageMso="SlideShowRehearseTimings"                   onAction="CalculateHours"/>        </group>        <group id="WageTools" label="工資工具">          <editBox id="Wage" label="計時工資:"                   image="dollar1.png" onChange="OnWageChanged"                   getText="GetWage"/>          <editBox id="Overtime" label="加班獎金:"                   image="dollar2.png" onChange="OnOvertimeChanged"                   getText="GetOvertime"/>          <button id="CalculatePay" label="計算報酬"                   size="large" imageMso="AcceptInvitation"                   onAction="CalculatePay"/>        </group>        <group id="SubmissionTools" label="提交工具">          <button id="SignTimecard" label="簽署時間卡片"                   size="large" image="signature.png"                   onAction="SignTimecard"/>          <button id="SubmitTimecard" label="提交時間卡片"                   size="large" image="submit.png"                   onAction="SubmitTimecard" getEnabled="IsTimecardSigned"                  screentip="確保在提交之前簽署時間                             卡片" />        </group>      </tab>      <tab idMso="TabPageLayoutExcel" getVisible="IsBuiltinTabVisible"/>      <tab idMso="TabData" getVisible="IsBuiltinTabVisible" />      <tab idMso="TabReview" getVisible="IsBuiltinTabVisible" />      <tab idMso="TabFormulas" getVisible="IsBuiltinTabVisible" />    </tabs>  </ribbon></customUI>
依次點擊此對話框以及隨后顯示的向導。您需要設置各種選項,例如您的加載項應安裝在哪些 Office 應用程序中,以及要使用哪種編程語言。在此示例中,我選擇使用 C#。
在創(chuàng)建加載項后,您應看到 Connect 類,該類實現(xiàn)標準的 COM 加載項 IDTExtensibility2 界面。這是您需要實現(xiàn) IribbonExtensibility 的對象。添加此界面并讓 Visual Studio 自動為您實現(xiàn)其方法。您最后應以與下面類似的代碼結束:
using Office = Microsoft.Office.Core;[GuidAttribute("E8407539-C642-43BB-8FCB-2E27A46179DE"),  ProgId("TimecardAddin.Connect")]public class Connect : Object, Extensibility.IDTExtensibility2,     Office.IRibbonExtensibility{    public string GetCustomUI(string RibbonID)    {        throw new Exception("未實現(xiàn)。");    }    // IDTExtensibility 方法}
IRibbonExtensibility 的唯一方法是 GetCustomUI,該方法將 RibbonX XML 作為字符串返回。它使用 RibbonID 參數(shù),該參數(shù)與“Microsoft.Word.Document”或“Microsoft.Excel.Workbook”字符串類似,而且主要用于編寫在多個應用程序或具有多種類型功能區(qū)的應用程序(例如 Microsoft Outlook)中運行的加載項。
如果您將 XML 文件作為名為 customui.xml 的“Embedded Resource”(嵌入資源)添加到項目中,您可以使用與下列類似的代碼從 GetCustomUI 中將其返回:
public string GetCustomUI(string RibbonID){    Assembly assembly = Assembly.GetExecutingAssembly();    using(Stream stream = assembly.GetManifestResourceStream(        "TimecardAddin.customui.xml"))    {        return new StreamReader(stream).ReadToEnd();    }}
此時,您可以構建加載項并安裝它。啟動 Excel 后,您應看到自定義 UI,但自定義圖像未加載以及單擊按鈕不執(zhí)行任何操作的情況除外。
XML 中所引用的所有回調函數(shù)都將調用失敗,由于您還未實現(xiàn)它們。如果啟用應用程序選項對話框的“Advanced”(高級)部分中的“Show add-in user interface errors”(顯示加載項用戶界面錯誤)選項,您將會看到一系列關于回調失敗的錯誤消息。您應確保在開發(fā) RibbonX 加載項時檢查此選項。這樣,在加載項出現(xiàn)問題時,您便會收到向您發(fā)出警報的大量錯誤消息。顯示的第一條錯誤消息解釋“onLoad”回調運行失敗的原因,因此我們先實現(xiàn)這個函數(shù)。

實現(xiàn)回調函數(shù)
功能區(qū)中的根 <customUI> 標記具有可選的 onLoad 回調,加載項可以實現(xiàn)該回調以獲得對 IRibbonUI 對象的引用。IRibbonUI 對象用于使緩存的回調返回值無效,而無論何時需更改加載項 UI 的狀態(tài)。我馬上就會詳細介紹如何使用它,目前暫時先將其塞入到成員變量中。將此代碼添加到 Connect 類:
Office.IRibbonUI m_Ribbon;public void OnLoad(Office.IRibbonUI ribbon){    m_Ribbon = ribbon;}
<customUI> 標記上的另一個可選回調是 loadImage,該回調是 COM 加載項為其控件加載圖標的方式。這就是 XML 中的 image="dollar1.png" 行起作用的位置。對于圖像屬性中指定的每個字符串,RibbonX 都會調用 loadImage 以加載該圖像。
可以用加載項所希望的任何方式來存儲圖像,但在此示例中,讓我們像使用 XML 那樣將圖像作為嵌入的資源進行添加。假定您已將 dollar1.png 作為資源添加到 TimecardAddin 程序集中,下面便是實現(xiàn) loadImage 回調的方法:
public Bitmap LoadImage(string imageName){    Assembly assembly = Assembly.GetExecutingAssembly();    Stream stream = assembly.GetManifestResourceStream(        "TimecardAddin." + imageName);    return new Bitmap(stream);}
關于此函數(shù),有幾個有趣的地方值得注意。首先,它將 System.Drawing.Bitmap 對象作為圖像返回。System.Drawing.Bitmap 是 2007 Office 版本的 RibbonX 支持的新功能,而且是為托管加載項返回圖像的最簡單也是最推薦的方法。非托管(C++ 和 Visual Basic 6.0)加載項可以為其圖像返回 IPictureDisp 對象,這些對象與 CommandBars 中所用對象的格式相同。
要注意的第二件事是您返回的只是一個包含位圖數(shù)據(jù)和透明度數(shù)據(jù)的圖像。我想您也發(fā)現(xiàn)了,對!不必再為您的 Office 加載項創(chuàng)建兩個獨立的“圖片”和“掩碼”圖標!有了 RibbonX,Office 現(xiàn)在支持具有 alpha 通道的全 32 位圖標。目前,PNG 格式具有對 alpha 通道的最佳工具支持,而且是 RibbonX 圖標的建議格式。
您需要實現(xiàn)的下一組回調是內置選項卡和自定義選項卡上的 getVisible 回調。內置選項卡都使用 IsBuiltinTabVisible,自定義選項卡則使用 IsCustomTabVisible,因為這兩個函數(shù)需要返回相反的值(編輯時間卡片時內置選項卡應隱藏,而自定義選項卡應顯示)。
通過將文件的 Category 屬性設置為 Timecard,加載項可以跟蹤特定的 Excel 工作簿是否為時間卡片。不具有此屬性的文件將被忽略。
IsBuiltinTabVisible 和 IsCustomTabVisible 函數(shù)都將使用幫助程序 IsTimecard 函數(shù):
public bool IsCustomTabVisible(Office.IRibbonControl tab) {    return IsTimecard(tab.Context as Excel.Window);}public bool IsBuiltinTabVisible(Office.IRibbonControl tab) {    return !IsTimecard(tab.Context as Excel.Window);}private bool IsTimecard(Excel.Window window){    if (null == window) return false;    Excel.Workbook workbook = (Excel.Workbook)window.Parent;    Office.DocumentProperties properties =         (Office.DocumentProperties)workbook.BuiltinDocumentProperties;    Office.DocumentProperty category = properties["Category"];    return (null != category && null != category.Value &&             category.Value.Equals("Timecard"));}
此代碼使用被傳遞到 RibbonX 回調的 IRibbonControl 的 Context 屬性。在大多數(shù) Office 應用程序中,Context 屬性等于 Window 對象。(Access 沒有 Window 對象,因此它在此處為 NULL,而在 Outlook 中,它等于 Inspector 對象。)加載項應使用 Window 對象來確定此 RibbonX 回調所引用的文檔,因為它并不始終等于 Application.ActiveDocument 屬性。Window 對象可以用于區(qū)分查看同一文檔的兩個不同窗口。
從 Window 對象您可以得到 Workbook 對象,從 Workbook 對象則可以得到 Category 屬性并檢查它是否等于 Timecard。

使 getVisible 回調值無效
如果您現(xiàn)在啟動 Excel,您將看到自定義選項卡為隱藏,而內置選項卡則為顯示。這是正確的,由于默認文檔不是時間卡片。如果您打開一個 Timecard 文檔,選項卡將不會顯示。為什么會這樣呢?
由于性能原因,RibbonX 緩存來自 get 回調的返回值。如果它不這樣做,它將一直回調加載項以防它需要切換其 UI 中的某項。加載項需要讓 Office 知道它何時想更改其 UI。
在這種情況下,便可使用之前討論的 IRibbonUI 對象。它包含兩個方法:Invalidate 和 InvalidateControl。Invalidate 方法將使所有緩存的回調無效,而 InvalidateControl 方法則使用控件 ID 參數(shù)并只使特定自定義控件的緩存回調無效。
無論何時在 Excel 中發(fā)生文檔切換,您都需要使選項卡的 getVisible 回調值無效,因為此時可能需要顯示 UI。Excel 提供了 WorkbookActivate 事件,您可以用它來實現(xiàn)此目的。在 OnStartupComplete 方法中為此事件添加一個處理程序:
public void OnStartupComplete(ref System.Array custom){    excelApplication.WorkbookActivate +=        new Excel.AppEvents_WorkbookActivateEventHandler(           OnWorkbookActivate);}void OnWorkbookActivate(Excel.Workbook Wb){    // 自定義選項卡可能需要在切換工作簿時變?yōu)榭梢姡?   // 以使緩存的 getVisible 值無效    m_Ribbon.Invalidate();}
幸運的是,只要您一鍵入 += 字符,Visual Studio IntelliSense 即會自動為您實現(xiàn)該事件處理程序,因此這很容易。
現(xiàn)在如果您打開 Excel 并在 Timecard 文檔和另一文檔之間切換,您將看到僅為時間卡片顯示自定義選項卡,而同時會隱藏內置選項卡。很好?,F(xiàn)在您只需要能夠使用加載項來首先創(chuàng)建時間卡片即可。
“New Timecard”(新建時間卡片)按鈕的回調相當簡單:它使用前面所示相同的 OnAction 簽名。它創(chuàng)建一個 Category 屬性等于 Timecard 的工作簿,并設置默認工作表:
public void NewTimecard(Office.IRibbonControl button){    Excel.Workbook timecard =         excelApplication.Workbooks.Add(Missing.Value);    Office.DocumentProperties properties =        (Office.DocumentProperties)timecard.BuiltinDocumentProperties;    properties["Category"].Value = "Timecard";    Excel.Worksheet timesheet =         (Excel.Worksheet)timecard.Worksheets[1];    NewTimesheet(timesheet);}
它使用幫助程序函數(shù)來初始化工作簿的第一個工作表中的時間表(“Clear Timecard”(清除時間卡片)按鈕會調用同樣的函數(shù))。

其他回調
其余的回調與“New Timecard”(新建時間卡片)按鈕的回調類似,因此我在此處未包括全部代碼,但有幾點值得一提。保存計時工資和加班乘數(shù)的 EditBox 比簡單按鈕稍微復雜些,因為它們需要兩個回調以確保工作正常。以下是用于工資框的回調:
double m_Wage = 5.25;public void OnWageChanged(Office.IRibbonControl c, string wage){    m_Wage = double.Parse(wage);}public string GetWage(Office.IRibbonControl c){    return m_Wage.ToString();}
只要用戶在工資框中鍵入新值,即會調用 OnWageChanged。此示例只轉換并記錄新值,但實際的加載項可能希望在接受新值之前,對其進行一些額外的邊界檢查和驗證。
GetWage 方法為 EditBox 提供了初始值。需要注意的重要一點是,IRibbonUI 對象使 UI 無效時也會調用它。加載項不應指望用戶輸入一直保留在 EditBox 內,因此建議使用與此示例中(OnWageChanged 和 GetWage)類似的一對 onChanged 和 getText 來跟蹤當前值。
加載項將工資值作為成員變量存儲在加載項中,這沒有問題,因為此值對于加載項是全局的且并不特定于文檔。如果此值與每個時間卡片關聯(lián),則您需要將該值存儲在與時間卡片相關聯(lián)的內存中,以便用戶在兩個時間卡片之間切換時可以正確地更新該值。
另一個有趣的控件是“Sign Timecard”(簽署時間卡片)按鈕。它彈出一個對話框,供用戶輸入其姓名然后將此姓名寫入到時間卡片中:
public void SignTimecard(Office.IRibbonControl button){    SignatureDialog sd = new SignatureDialog();    if (DialogResult.OK == sd.ShowDialog())    {        string signature = sd.GetSignature();        timesheet.get_Range("E" + (daycount + 5),         Missing.Value).Formula = signature;        m_Ribbon.InvalidateControl("SubmitTimecard");    }}
它還調用 SubmitTimecard 按鈕上的 IRibbonUI.InvalidateControl?!癝ubmit”(提交)按鈕將禁用,直到使用檢查簽名的 getEnabled 函數(shù)簽署了時間卡片。在簽名后,您需要使此 getEnabled 返回值無效以重新啟用該按鈕。
由于僅在單擊“Sign Timecard”(簽署時間卡片)按鈕時,加載項才調用 InvalidateControl,因此如果用戶手動將簽名鍵入到時間卡片單元格中,則不會啟用“Submit”(提交)按鈕(如果用戶刪除其簽名,則會禁用該按鈕)。如果您希望此按鈕工作,每當簽名單元格被修改,我們都可以掛接 SheetChanged 事件,然后調用 InvalidateControl。

總結
這就是有關 Timecard 加載項的所有內容。整個加載項僅有幾百行代碼,其中包括由 Visual Studio 自動生成的全部代碼。不可否認,它相當簡陋,要實際應用還需進行大量的錯誤檢查和代碼驗證,但它演示了使用 RibbonX 來利用 Office 作為您自己的應用程序的平臺是多么容易。如果您想親自嘗試一下,請下載源代碼。
本文僅簡單介紹了 RibbonX 中的功能,因此如果您需要更多詳細信息和示例代碼,請訪問 MSDN 上的官方頁面(英文)。該網(wǎng)頁上還有指向完整 RibbonX 文檔、控件 ID 的列表、示例加載項和 RibbonX 相關博客的鏈接。

本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
細品RibbonX(6):初識RibbonX
VBA專題10-8:使用VBA操控Excel界面之在功能區(qū)中添加內置控件
什么是“開發(fā)工具”選項?OFFICE 2010如何將其顯示在我的 Office 中?
VSTO之旅系列(三):自定義Excel UI
20.4.1 組合內置Ribbon - 51CTO.COM
在Excel 中自定義菜單欄和工具欄-添加、刪除、禁止等
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服