程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 淺談Excel開發:二 Excel 菜單系統

淺談Excel開發:二 Excel 菜單系統

編輯:C#入門知識

在開始Excel開發之前,需要把架子搭起來。最直接的那就是Excel裡面的菜單了,他向用戶直觀的展現了我們的插件具有哪些功能。菜單出來之後我們就可以實現裡面的事件和功能了。Excel菜單有兩種形式,一種是Excel 2003及之前的傳統菜單樣式,一種是Excel 2007及之後的Ribbon菜單。本文首先講解Excel 2007中菜單的創建,包括使用Visual Studio可視化設計菜單,菜單的RibbonXml配置,然後講解如何在Excel 2003中創建自定義菜單。最後演示如何使用SharedAddin技術將兩者結合起來,即在2003版本中顯示原始的菜單樣式,在以2003上版本中動態加載Ribbon菜單,從而達到版本的兼容。

要演示菜單的創建,我們首先創建一個VSTO程序,如圖在VS中創建一個Excel外接程序:

2.1 Tab控件

在Office中Ribbon菜單時可以通過RibbonXML進行配置,也就是說,上面的可視化界面設計其實是為我們提供了編輯RibbonXML的設計時支持。其實我們也可以直接創建一個XML文件進行設計,然後在代碼中進行加載,同樣能夠實現這樣的功能。在有些情況下,比如我們創建SharedAddin程序時,根本沒有設計時支持。所以了解RibbonXML對於創建可兼容多版本Excel菜單系統顯得尤為重要。

要創建RibbonXML最好的做法是對著新建的可視化菜單,然後右鍵->將功能區導出到XML。然後項目會自動創建Ribbon.xml和Ribbon.cs文件,其中Ribbon.xml是布局文件,Ribbon.cs是事件處理代碼。

運行程序,即可看到如下效果:

其中,imageName即為Button控件的image屬性要設置的圖片名稱。資源文件圖片,要設置為嵌入的資源。所有的按鈕的單擊事件,我們使用GeneralButton_Click事件來處理。運行程序,我們又看到了之前采用設計器時編輯的菜單時的界面了。

由於Excel2003及以下版本不支持Ribbon菜單,所以以上的程序在03版本下並不能運行。但是,如果開發企業級應用的話,仍不能忽視廣大使用 Office 2003 版本的客戶,所以您還需要創建2003下面的菜單系統。下面就介紹如何在Excel2003系統中創建Excel菜單及工具條。

要創建在Excel 03下的插件,我們可以創建Shared Add-in程序,如下圖,首先新建一個名為YYSharedAddin的Shared Add-in項目:

在OnConnection方法中,我們首先判斷Excel的版本號,版本號可以通過Version對象獲取,如果版本號為11,即為2003版本的Excel,我們需要手動的動態創建菜單和工具條。我們新建了一個名為MenuDesigner的用來創建菜單和工具條的類,在其構造函數中傳入了applicationObject對象。

添加菜單

我們把添加菜單放到了MenuDesigner的AddMenus方法中。Excel中的一個菜單項和子菜單其實都是一個MSOffice.CommandBarPopup對象,菜單項裡面的菜單按鈕是MSOffice.CommandBarButton對象。首先我們定義菜單項以及菜單按鈕,這裡只列出部分。

MSOffice.YYMenu = ;
MSOffice.btnQuoteFunctionMenuCommand = ;
MSOffice.btnQuoteSinaFunctionMenuCommand = ;
MSOffice.btnQuoteYahooFunctionMenuCommand = ;

在創建菜單時,我們要首先創建YYMenu對象,然後再在該對象上添加菜單項。創建YYMenu菜單的方法如下:

AddMenus()
{
    MSOffice.menubar = (MSOffice.)application.CommandBars.ActiveMenuBar;
    controlCount = menubar.Controls.Count;
    menuCaption = ;
    {
        YYMenu = (MSOffice.)
            application.CommandBars.ActiveMenuBar.FindControl(
            MSOffice..msoControlPopup, System..Missing, menuTag, , );
    }
    { }

    (YYMenu != )
    {
        YYMenu.Delete(.Missing);
    }
    YYMenu = (MSOffice.)menubar.Controls.Add(MSOffice..msoControlPopup, missing, missing, controlCount, );
    YYMenu.Tag = menuTag;
    YYMenu.Caption = menuCaption;
    YYMenu.BeginGroup = ;

    LoginGroup();
    FinancialGroup();
    MapServiceGroup();
    WeatherReportGroup();
    AboutGroup();
}

需要注意的是,在創建菜單之前,我們需要判斷之前是否已經存在相同Tag值得菜單,如果存在,需要先將之前創建的菜單項刪除,然後再重新創建。否則,在用戶在Com加載項中顯示或者隱藏菜單項時,會重復創建菜單項。創建完主菜單後,我們可以在主菜單上創建子菜單了。這些方法都寫到了最後的幾個以Group結尾的方法中。現在以創建財務項菜單的FinancalGroup方法為例講解。

FinancialGroup()
{
    MSOffice.realTimeButton = AddPopupButton(YYMenu.Controls, .Quote);
    realTimeButton.BeginGroup = ;
    btnQuoteFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, .Quote, YYSharedAddin.Properties..QuoteReal);
    btnQuoteSinaFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, .QuoteSina, YYSharedAddin.Properties..SinaQuote_64);
    btnQuoteSinaFunctionMenuCommand.BeginGroup = ;
    btnQuoteYahooFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, .QuoteYahoo, YYSharedAddin.Properties..Yahoo_Quote);

    MSOffice.historyButton = AddPopupButton(YYMenu.Controls, .QuoteHistory);
    realTimeButton.BeginGroup = ;
    btnQuoteHistoryFunctionMenuCommand = AddCommandButton(historyButton.Controls, .QuoteHistory, YYSharedAddin.Properties..QuoteHist);
    btnQuoteHistorySinaFunctionMenuCommand = AddCommandButton(historyButton.Controls, .QuoteHistorySina, YYSharedAddin.Properties..SinaQuote_64);
    btnQuoteHistorySinaFunctionMenuCommand.BeginGroup = ;
    btnQuoteHistoryYahooFunctionMenuCommand = AddCommandButton(historyButton.Controls, .QuoteHistoryYahoo, YYSharedAddin.Properties..Yahoo_HistoryQuote);

    MSOffice.importButton = AddPopupButton(YYMenu.Controls, .Import);
    importButton.BeginGroup = ;
    btnImportFromLocalMenuCommand = AddCommandButton(importButton.Controls, .ImportFromLocal, YYSharedAddin.Properties..ImportFromDisk);
    btnImportFromWebMenuCommand = AddCommandButton(importButton.Controls, .ImportFromWeb, YYSharedAddin.Properties..ImportFromWeb);
}

對於財務大類菜單,其中有三個一級菜單,分別是實時行情,歷史行情,導入。創建一級菜單的方法AddPopupButton代碼為:

MSOffice.AddPopupButton(MSOffice.controls, menu)
{
    tag = menu.ToString();
    caption = .Empty;
    .menus.TryGetValue(tag, caption);
    MSOffice.command = ;
    {
        command = controls[caption] MSOffice.;
    }
    { }
    (command == )
    {
        command = controls.Add(MSOffice..msoControlPopup, .Missing, .Missing, .Missing, .Missing) MSOffice.;
        command.Caption = caption;
    }
    command;
}

其中第一個參數為最大的根節點菜單YYMenu對象的所有Controls容器。所以創建第一個實時行情一級菜單的方法為:

MSOffice.realTimeButton = AddPopupButton(YYMenu.Controls, .Quote);
realTimeButton.BeginGroup = ;

得到realTimeButton這個一級菜單之後,我們將其BeginGroup屬性設置為true表示在之前添加一個Seperator控件(一條橫線或者豎線)。有了這個realTimeButton一級菜單之後,我們可以在該對象上創建三個二級菜單按鈕項。

btnQuoteFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, .Quote, YYSharedAddin.Properties..QuoteReal);
btnQuoteSinaFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, .QuoteSina, YYSharedAddin.Properties..SinaQuote_64);
btnQuoteSinaFunctionMenuCommand.BeginGroup = ;
btnQuoteYahooFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, .QuoteYahoo, YYSharedAddin.Properties..Yahoo_Quote);

創建子菜單按鈕的方法封裝到了AddCommandButton方法中,方法第一個參數為第一級子菜單的所有控件的容器類。

MSOffice.AddCommandButton(MSOffice.controls, menu, System.Drawing.icon)
{
    tempName = menu.ToString();
    tag = .Format(, menu, .Now.ToBinary());
    caption = .Empty;
    .menus.TryGetValue(tempName, caption);
    MSOffice.command = ;
    {
        command = controls[caption] MSOffice.;
        command.Tag = tag;
        command.Click += MSOffice.(command_Click);
    }
    { }
    (command == )
    {
        command = controls.Add(MSOffice..msoControlButton, .Missing, .Missing, .Missing, .Missing) MSOffice.;
        command.Style = MSOffice..msoButtonIconAndCaption;
        command.Caption = caption;
        command.Tag = tag;
        command.Picture = .ImageToPictureDisp(icon);
        command.Click += MSOffice.(command_Click);
    }
    command;
}

在創建菜單按鈕時,我們需要先判斷當前的菜單中是否有該菜單項,如果有直接使用。否則創建新的對象。這裡有幾個地方需要注意,首先是CommandBarButton 的Tag屬性,該屬性應該加上一個唯一標志,比如當前時間,或者GUID,然後帶上該菜單的名稱等信息。加唯一標志的目的是每一次在創建菜單時保證是唯一的,否則會出現菜單只會響應一次按鈕點擊事件等奇怪的問題。其次設置按鈕的Style為MSOffice.MsoButtonStyle.msoButtonIconAndCaption 既帶圖片又有文字的時候,Picture屬性為想要顯示在按鈕前面的圖片,該對象是一個stdole.IPictureDisp類型的對象,您需要進行一下轉換。其次直接設置圖片會使得圖片中的背景色不會透明,背景色為Office的默認風格顏色,如果要將背景色透明,需要設置Mask屬性,Mask屬性也是一張圖片。該圖片為帶顯示圖片的蒙版,即原始圖片中需要顯示的地方,用黑色表示,那麼其余地方就會透明顯示,具體使用方式您可以參看這篇文章,這裡為了簡化,不做處理。

添加工具條

工具條其實就是一個大的一級菜單,和創建菜單一樣,我們將創建工具條的代碼封裝到了AddToolBars方法中,該方法代碼如下:

AddToolBars()
{
    {
        YYToolBar = application.CommandBars[];
    }
    { }

    (YYToolBar == )
    {
        YYToolBar = application.CommandBars.Add(, MSOffice..msoBarTop, , );
    }
    LoginGroup_ToolBar();
    FinancialGroup_ToolBar();
    MapServiceGroup_ToolBar();
    WeatherReportGroup_ToolBar();
    AboutGroup_ToolBar();

    YYToolBar.Visible = ;
}

我們首先需要創建一個大的工具條,和創建菜單類似,在創建工具條之前,我們需要定義好所有的工具條中的按鈕,注意,該按鈕對象不能和菜單項裡面的對象共用,否則會導致事件注冊被沖掉的情況。

MSOffice.YYToolBar;
MSOffice.btnQuoteFunctionToolBarCommand = ;
MSOffice.btnQuoteSinaFunctionToolBarCommand = ;
MSOffice.btnQuoteYahooFunctionToolBarCommand = ;

創建好YYToolBar對象後,在該對象的基礎上創建工具條裡面的工具項就和創建字菜單類似了,這裡就不再贅述了。

現在我們來看在Excel2003下面的效果。由於我們創建的SharedAddin程序,我們在調試的時候,需要設置啟動程序,Visual Studio 給我們設置的默認啟動程序是Visual Studio本身。這裡我們將默認程序指定為Excel 2003 的可執行文件,如下圖:

前面介紹了在2003以上版本的Ribbon菜單創建和在2003版本下面的傳統菜單項的創建。一個良好的Excel應用程序應該會根據版本的不同而展現不同的菜單形式。如果您用VSTO創建的話,那麼可能在03版本上就不能很好的支持,因為03版本不支持Ribbon菜單。所以要想兼容所有的Excel版本,可以創建Shared Add-in工程。第二部分已經講解了如何在SharedAddin中創建傳統菜單的方法,要兼容03以上版本,我們只需要在SharedAddin中加載第一部分創建好的RibbonXML即可。

要讓SharedAddin能在03以上版本中渲染Ribbon菜單,我們需要讓Connect類實現Office.IRibbonExtensibility接口。由於之前生成的Ribbon.cs類已經實現了該接口,所以最簡單的方法是:將之前創建好的Ribbon.xml及Ribbon.cs拷貝到SharedAddin工程項目中來。並將Ribbon.xml設置為嵌入的資源。將Ribbon.cs 的命名空間改為和Connect.cs一致的命名空間,然後利用Partial關鍵字,將Ribbon類名稱改為partial Connect類。如下:

[()]
: Office.{
    Office.ribbon;
    IRibbonExtensibility 成員

    GetCustomUI(ribbonID)
    {
        GetResourceText();
    }
    功能區回調
    Ribbon_Load(Office.ribbonUI)
    {
        .ribbon = ribbonUI;
    }

    LoadImage(imageName)
    {
        assembly = .GetExecutingAssembly();
        stream = assembly.GetManifestResourceStream(+ imageName);
        .FromStream(stream);
    }

    GeneralButton_Click(Office.control)
    {
        {
            .Show(+ control.Id);
        }
        (ex)
        {

        }
    }
    幫助器

    GetResourceText(resourceName)
    {
        asm = .GetExecutingAssembly();
        [] resourceNames = asm.GetManifestResourceNames();
        (i = 0; i < resourceNames.Length; ++i)
        {
            (.Compare(resourceName, resourceNames[i], .OrdinalIgnoreCase) == 0)
            {
                (resourceReader = (asm.GetManifestResourceStream(resourceNames[i])))
                {
                    (resourceReader != )
                    {
                        resourceReader.ReadToEnd();
                    }
                }
            }
        }
        ;
    }

    }

我們需要注意的是,要設置好正確的資源名稱,您可以通過GetManifestResourceNames 來查看該程序集中的所有的資源名稱。

現在,將啟動項目設置為2007 或者2010版本的Excel,現在菜單又變成Ribbon風格的了:

本文介紹了Excel中的菜單系統。首先介紹了使用Visual Studio設計時支持的Ribbon菜單的創建,通過拖拉控件及設置屬性,可以創建出和Office內置菜單相媲美的自定義菜單。然後介紹了Ribbon菜單的基礎Ribbon XML文件,隨後講解了如何在VSTO中手動加載Ribbon菜單。然而Ribbon菜單僅在2003以上版本的Excel中支持。為了解決Excel 2003下菜單創建的問題,本文展示了如何創建Excel Shared Add-in程序,並演示了如何創建傳統的菜單項和工具欄。最後為了兼容所有的Excel版本,在SharedAddin中展示了如何加載Ribbon XML,使得我們的Excel插件對於不同的Excel版本,能夠展現出不同風格的菜單項。

現在我們的插件架子已經搭好了,下文我會講解Excel的對象模型,介紹Excel中的幾個核心對象,如WorkBook,WorkSheet,Range對象等,這些對象無論是您進行何種類型的Excel開發,都會遇到,這些對象也是您進行Excel開發的重要基礎,敬請期待。

本文代碼點擊此處下載,希望本文對您了解Excel菜單系統有所幫助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved