浅谈Excel开发:二 Excel 菜单系统

在开始Excel开发之前,需要把架子搭起来。最直接的那就是Excel里面的菜单了,他向用户直观的展现了我们的插件具有哪些功能。菜单出来之后我们就可以实现里面的事件和功能了。Excel菜单有两种形式,一种是Excel 2003及之前的传统菜单样式,一种是Excel 2007及之后的Ribbon菜单。本文首先讲解Excel 2007中菜单的创建,包括使用Visual Studio可视化设计菜单,菜单的RibbonXml配置,然后讲解如何在Excel 2003中创建自定义菜单。最后演示如何使用SharedAddin技术将两者结合起来,即在2003版本中显示原始的菜单样式,在以2003上版本中动态加载Ribbon菜单,从而达到版本的兼容。

一 Excel 的Ribbon菜单及Ribbon Xml文件

要演示菜单的创建,我们首先创建一个VSTO程序,如图在VS中创建一个Excel外接程序:

Create VSTO Project

然后接下来,添加项,添加一个Ribbon菜单:

Create Ribbon Menu

在创建菜单之前,需要明确我们的插件具有哪些模块。这里为了演示如何创建菜单以及后面的功能点,我们的插件打算做四个功能点。 首先是财经模块,包括从一些开放的财经API如新浪财经API,雅虎API中获取实时或者历史行情数据;地图模块,包括地图显示,地址检索,专题制图等;天气模块,获取天气,天气保表;系统模块,包括登录,帮助,关于模块等。确定好功能点之后,就可以开始创建菜单了。

添加了Ribbon菜单之后,就可以打开ToolBox开始设计了,如下图。下面介绍各个菜单项的功能及设计要点。

基本控件

2.1 Tab控件

VSTO Design Interface

首先介绍的是RibbonTab控件,它是所有控件的容器,当我们添加一个Ribbon菜单的时候,VS默认会给我们创建一个RibbonTab控件,一个VSTO项目可以创建多个Tab控件,您需要做的只是从ToolBox中推拽一个Tab至设计界面上即可。Tab控件有一些属性。

VSTO Tab control Property

其中比较重要的属性为ControlIdType,如果类型是Office的话,他会嵌入到Office内置系统的 Tab页中,而不是默认的新创建一个以Label为名称的Tab页。下图是ControlIdType为Office的效果,如果PositionType属性设置为Default的话,会出现在Office加载项 这个标签页中。

TabControlTypeOffice

如果将ControlIdType设置为Custom,则在界面上会显示以Label命名的一个新的Tab页,这里将Label改为歪歪插件。效果如下图:

TabControlTypeCustom

一般的,我们会采用Custom的方式,让我们的插件以独立的Tab页展现出来。

Tab控件还有一个重要的名为Position的属性,他决定了我们的Tab在哪个地方展现,PositionType的默认值为Default,这时,如果ControlIdType为Office,我们的插件会在加载项中显示,如果为Custom,插件会显示在Office里面的最后一个加载项后面,如果有多个加载项,则按顺序往后面排列。PositionType属性还有BeforeOfficeId和AfterOfficeId两值,设置这两个属性时,需要指定OfficeId,Office内置的菜单的ID值,您可以到MSDN上下载。指定好OfficeId后,我们的Tab也会在该内置Tab页里面,前面或者后面显示。一般的,我们保持这个属性为空即可。让我们的插件在Office系统Tab页之后显示。

2.2 Group控件

Group控件的作用是将我们的功能进行分组。回到我们之前的规划,我们的歪歪插件有财经,地图,天气,关于这几大功能。所以我们需要在界面上放置4个Group控件,并对其进行命名。

groupcontrol

2.3 Menu控件和SpliterButton控件

在分好类之后,我们需要对每个分类的细小功能进行设计,这里面我们需要放置各种控件,首先我们可能会接触到的就是Menu控件,里面可以包含Button,SplitButton等。我们规划的财经项主要包括,实时行情,历史行情和导入功能。实时行情和历史行情包括从Sina或者Yahoo财经API接口中获取所有股票的实时和历史行情数据,导入功能即是从本地或者网络上导入数据。所以在页面上添加三个Menu控件。

Menu Property

Menu控件几个比较重要的属性,一个是ControlSize,它确定了控件的大小,一般地,如果功能较重要,或者是有比较明显的分类用途,使用RibbonControlSizeLarge。然后需要设置菜单的图标,可以指定自定义的图片,也可以使用默认的Office内置的菜单的图片,如果要使用内置的图片,需要设置OfficeImageId,具体内置Id及图片可以查看该网址。一般地,我们会为我们的菜单设计图标,您只需要指定其Image属性即可。

SplitButton控件和Menu控件类似,它可以包含Button,Seperator控件,不同的是,SplitButton控件本身自己可以响应Click事件,通常在Menu中如果需要将该菜单项中常用的功能设置为默认的,那么可以使用SplitButton控件,将最常用的功能设置到该控件的Click事件上来。

2.4 Button,Seperator控件

Button控件是最基础的响应单击事件的UI控件。点开Menu的下拉图标,然后向里面添加Button按钮即可,可以设置按钮的Image属性。在设计按钮的时候,可能我们需要对其进行分组,这时候,使用Seperator控件是一种比较好的选择,直接在ToolBox中拖动一个Seperator控件到界面上想分割的地方即可。默认情况下Seperator控件是一条竖线,但是当设置Seperator控件的Title属性时,他可以以文本的形式来进行分割,这和其他系统中的Seperator控件不一样。

VSTO Spliter

同理,按照规划,我们将所有的菜单设计好,并注册其Click事件。这里只讲解了这几个基本的菜单项控件,更多的控件您可能以自己往界面上拖拽试试看,利用这些内置的控件,您可以设计出和Office内置的Ribbon菜单媲美的自定义菜单界面来。

YY插件菜单 

RibbonXml

在Office中Ribbon菜单时可以通过RibbonXML进行配置,也就是说,上面的可视化界面设计其实是为我们提供了编辑RibbonXML的设计时支持。其实我们也可以直接创建一个XML文件进行设计,然后在代码中进行加载,同样能够实现这样的功能。在有些情况下,比如我们创建SharedAddin程序时,根本没有设计时支持。所以了解RibbonXML对于创建可兼容多版本Excel菜单系统显得尤为重要。

要创建RibbonXML最好的做法是对着新建的可视化菜单,然后右键->将功能区导出到XML。然后项目会自动创建Ribbon.xml和Ribbon.cs文件,其中Ribbon.xml是布局文件,Ribbon.cs是事件处理代码。

VSTO Ribbon2XML

打开Ribbon.xml可以看到如下代码,可以看到这个UI界面的展现即是使用了该XML文件来进行渲染的,其中在XML中还可以声明一些事件,后面会讲。

VSTO RibbonXML

现在,如何在我们的应用程序中加载该RibbonXML并渲染出Ribbon菜单呢?首先,我们将之前的添加的可视化设计的Ribbon菜单YYMenu.cs排除到项目外。然后转到ThisAddIn.cs中,覆写Office.IRibbonExtensibility 接口的CreateRibbonExtensibilityObject方法,实例化自动生成的Ribbon类,然后返回。

private Ribbon customerRibbon;

protected override Office.IRibbonExtensibility CreateRibbonExtensibilityObject()
{
    customerRibbon = new Ribbon();
    return customerRibbon;
}

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

YY插件菜单 No Image

可以看到图片不见了,这是因为在导出功能区为XML的时候,VS没有帮我们处理图片,所以需要我们自己来添加。在RibbonXML文档中, customUI节点下有loadImage事件,Button有getImage事件和image属性。customUI节点的loadImage方法和子节点的image属性一起使用,image属性作为loadImage方法的参数。

VSTO RibbonXML GetImage

loadImage方法如下:

public Image LoadImage(string imageName)
{
    Assembly assembly = Assembly.GetExecutingAssembly();
    //String[] all =assembly.GetManifestResourceNames();//GetResourceName
    Stream stream = assembly.GetManifestResourceStream("YYAddIn.Resources." + imageName);
    return Image.FromStream(stream);
}

其中,imageName即为Button控件的image属性要设置的图片名称。资源文件图片,要设置为嵌入的资源。所有的按钮的单击事件,我们使用GeneralButton_Click事件来处理。运行程序,我们又看到了之前采用设计器时编辑的菜单时的界面了。

二 Excel 2003下面的菜单系统

创建工程

由于Excel2003及以下版本不支持Ribbon菜单,所以以上的程序在03版本下并不能运行。但是,如果开发企业级应用的话,仍不能忽视广大使用 Office 2003 版本的客户,所以您还需要创建2003下面的菜单系统。下面就介绍如何在Excel2003系统中创建Excel菜单及工具条。

要创建在Excel 03下的插件,我们可以创建Shared Add-in程序,如下图,首先新建一个名为YYSharedAddin的Shared Add-in项目:

SharedAddin

然后下一步下一步, 设置编程语言,我们这里选择C#

SharedAddinStep2 

下一步,设置插件的目标应用程序,可以看到,我们的Shared Add-in程序可以为多个目标应用程序编写同一个插件,这在前一篇文章中介绍SharedAddin和VSTO的差别时已经介绍过了。因为我们主要是编写Excel插件,所以仅勾选Excel即可。

SharedAddinStep3

下一步,设置Addin的展现名称和在编程时的名称

SharedAddinStep4

创建完成之后,我们可以看到工程项目非常简单,只有一个Connect.cs文件。打开该文件,可以看到其中实现了Extensibility.IDTExtensibility2 接口,所有Office应用程序都是用IDTExtensibility2接口与COM加载项进行通信的,该接口提供了一种通用的初始化机制,并具有在Office应用程序的对象模型中传递数据的能力,因此Com加载项可以与Office应用程序通信,该接口中有5个方法,分别是:

IDTExtensibility2 接口

Office在对Com加载项进行实例化时,会创建Connect类,注意我们不能用Connect的构造函数创建类的实例,应该在OnConnection方法中进行初始化操作,比如菜单项的加载,自定义函数的加载,变量的初始化等等;类似的,加载项的关闭不能调用析构函数,而要用OnDisconnection方法,在该方法中需要释放非托管的资源,进行资源清理等一系列操作。下图展示了这5个方法的执行顺序。该图引用了MYM]Brooks同学博文中的图片。

SharedAddin IDTExtensibility接口方法的执行顺序

由分析得之,我们对菜单及工具栏的初始化,需要放到OnConnection方法中。

在OnConnection方法中,有一个很重要的参数就是application,我们声明一个类型为

Microsoft.Office.Interop.Excel.Application的applicationObject对象,然后将这个对象保存起来,以备后面创建菜单以及对Excel进行操作时使用。

private Application applicationObject;

/// <summary>
///      Implements the OnConnection method of the IDTExtensibility2 interface.
///      Receives notification that the Add-in is being loaded.
/// </summary>
/// <param term='application'>
///      Root object of the host application.
/// </param>
/// <param term='connectMode'>
///      Describes how the Add-in is being loaded.
/// </param>
/// <param term='addInInst'>
///      Object representing this Add-in.
/// </param>
/// <seealso class='IDTExtensibility2' />
public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
{
    applicationObject = application as Application;
    addInInstance = addInInst as COMAddIn;

    if (applicationObject.Version == "11.0")
    {
        if (menuDesigner == null)
        {
            menuDesigner = new MenuDesigner(applicationObject);
        }
        menuDesigner.AddMenus();
        menuDesigner.AddToolBars();
    }
}

在OnConnection方法中,我们首先判断Excel的版本号,版本号可以通过Version对象获取,如果版本号为11,即为2003版本的Excel,我们需要手动的动态创建菜单和工具条。我们新建了一个名为MenuDesigner的用来创建菜单和工具条的类,在其构造函数中传入了applicationObject对象。

添加菜单

我们把添加菜单放到了MenuDesigner的AddMenus方法中。Excel中的一个菜单项和子菜单其实都是一个MSOffice.CommandBarPopup对象,菜单项里面的菜单按钮是MSOffice.CommandBarButton对象。首先我们定义菜单项以及菜单按钮,这里只列出部分。

//YY插件菜单
MSOffice.CommandBarPopup YYMenu = null;
//实时行情函数菜单按钮
MSOffice.CommandBarButton btnQuoteFunctionMenuCommand = null;
//Sina实时行情函数菜单按钮
MSOffice.CommandBarButton btnQuoteSinaFunctionMenuCommand = null;
//Yahoo实时行情函数菜单按钮
MSOffice.CommandBarButton btnQuoteYahooFunctionMenuCommand = null;

在创建菜单时,我们要首先创建YYMenu对象,然后再在该对象上添加菜单项。创建YYMenu菜单的方法如下:

public void AddMenus()
{
    MSOffice.CommandBar menubar = (MSOffice.CommandBar)application.CommandBars.ActiveMenuBar;
    int controlCount = menubar.Controls.Count;
    string menuCaption = "歪歪插件";
    // Add the menu.
    try
    {
        YYMenu = (MSOffice.CommandBarPopup)
            application.CommandBars.ActiveMenuBar.FindControl(
            MSOffice.MsoControlType.msoControlPopup, System.Type.Missing, menuTag, true, true);
    }
    catch { }

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

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

需要注意的是,在创建菜单之前,我们需要判断之前是否已经存在相同Tag值得菜单,如果存在,需要先将之前创建的菜单项删除,然后再重新创建。否则,在用户在Com加载项中显示或者隐藏菜单项时,会重复创建菜单项。创建完主菜单后,我们可以在主菜单上创建子菜单了。这些方法都写到了最后的几个以Group结尾的方法中。现在以创建财务项菜单的FinancalGroup方法为例讲解。

private void FinancialGroup()
{
    //实时行情
    MSOffice.CommandBarPopup realTimeButton = AddPopupButton(YYMenu.Controls, MenuNameEnum.Quote);
    realTimeButton.BeginGroup = true;
    //添加子菜单
    btnQuoteFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, MenuNameEnum.Quote, YYSharedAddin.Properties.Resources.QuoteReal);
    btnQuoteSinaFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, MenuNameEnum.QuoteSina, YYSharedAddin.Properties.Resources.SinaQuote_64);
    btnQuoteSinaFunctionMenuCommand.BeginGroup = true;
    btnQuoteYahooFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, MenuNameEnum.QuoteYahoo, YYSharedAddin.Properties.Resources.Yahoo_Quote);

    //历史行情
    MSOffice.CommandBarPopup historyButton = AddPopupButton(YYMenu.Controls, MenuNameEnum.QuoteHistory);
    realTimeButton.BeginGroup = true;
    //添加子菜单
    btnQuoteHistoryFunctionMenuCommand = AddCommandButton(historyButton.Controls, MenuNameEnum.QuoteHistory, YYSharedAddin.Properties.Resources.QuoteHist);
    btnQuoteHistorySinaFunctionMenuCommand = AddCommandButton(historyButton.Controls, MenuNameEnum.QuoteHistorySina, YYSharedAddin.Properties.Resources.SinaQuote_64);
    btnQuoteHistorySinaFunctionMenuCommand.BeginGroup = true;
    btnQuoteHistoryYahooFunctionMenuCommand = AddCommandButton(historyButton.Controls, MenuNameEnum.QuoteHistoryYahoo, YYSharedAddin.Properties.Resources.Yahoo_HistoryQuote);

    //导出
    MSOffice.CommandBarPopup importButton = AddPopupButton(YYMenu.Controls, MenuNameEnum.Import);
    importButton.BeginGroup = true;
    btnImportFromLocalMenuCommand = AddCommandButton(importButton.Controls, MenuNameEnum.ImportFromLocal, YYSharedAddin.Properties.Resources.ImportFromDisk);
    btnImportFromWebMenuCommand = AddCommandButton(importButton.Controls, MenuNameEnum.ImportFromWeb, YYSharedAddin.Properties.Resources.ImportFromWeb);
}

对于财务大类菜单,其中有三个一级菜单,分别是实时行情,历史行情,导入。创建一级菜单的方法AddPopupButton代码为:

/// <summary>
/// 添加子菜单项
/// </summary>
/// <param name="controls">该字菜单的父菜单容器</param>
/// <param name="menu">菜单名称</param>
/// <returns></returns>
private MSOffice.CommandBarPopup AddPopupButton(MSOffice.CommandBarControls controls, MenuNameEnum menu)
{
    String tag = menu.ToString();
    String caption = String.Empty;
    Menus.menus.TryGetValue(tag, out caption);
    MSOffice.CommandBarPopup command = null;
    try
    {
        command = controls[caption] as MSOffice.CommandBarPopup;
    }
    catch { }
    if (command == null)
    {
        command = controls.Add(MSOffice.MsoControlType.msoControlPopup, Type.Missing, Type.Missing, Type.Missing, Type.Missing) as MSOffice.CommandBarPopup;
        command.Caption = caption;
    }
    return command;
}

其中第一个参数为最大的根节点菜单YYMenu对象的所有Controls容器。所以创建第一个实时行情一级菜单的方法为:

//实时行情
MSOffice.CommandBarPopup realTimeButton = AddPopupButton(YYMenu.Controls, MenuNameEnum.Quote);
realTimeButton.BeginGroup = true;

得到realTimeButton这个一级菜单之后,我们将其BeginGroup属性设置为true表示在之前添加一个Seperator控件(一条横线或者竖线)。有了这个realTimeButton一级菜单之后,我们可以在该对象上创建三个二级菜单按钮项。

//添加子菜单
btnQuoteFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, MenuNameEnum.Quote, YYSharedAddin.Properties.Resources.QuoteReal);
btnQuoteSinaFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, MenuNameEnum.QuoteSina, YYSharedAddin.Properties.Resources.SinaQuote_64);
btnQuoteSinaFunctionMenuCommand.BeginGroup = true;
btnQuoteYahooFunctionMenuCommand = AddCommandButton(realTimeButton.Controls, MenuNameEnum.QuoteYahoo, YYSharedAddin.Properties.Resources.Yahoo_Quote);

创建子菜单按钮的方法封装到了AddCommandButton方法中,方法第一个参数为第一级子菜单的所有控件的容器类。

private MSOffice.CommandBarButton AddCommandButton(MSOffice.CommandBarControls controls, MenuNameEnum menu, System.Drawing.Image icon)
{
    string tempName = menu.ToString();
    String tag = String.Format("{0}|{1}", menu, DateTime.Now.ToBinary());
    String caption = String.Empty;
    Menus.menus.TryGetValue(tempName, out caption);
    MSOffice.CommandBarButton command = null;
    try
    {
        command = controls[caption] as MSOffice.CommandBarButton;
        command.Tag = tag;
        command.Click += new MSOffice._CommandBarButtonEvents_ClickEventHandler(command_Click);
    }
    catch { }
    if (command == null)
    {
        command = controls.Add(MSOffice.MsoControlType.msoControlButton, Type.Missing, Type.Missing, Type.Missing, Type.Missing) as MSOffice.CommandBarButton;
        command.Style = MSOffice.MsoButtonStyle.msoButtonIconAndCaption;
        command.Caption = caption;
        command.Tag = tag;
        command.Picture = ImageConverterHelper.ImageToPictureDisp(icon);
        command.Click += new MSOffice._CommandBarButtonEvents_ClickEventHandler(command_Click);
    }
    return command;
}

在创建菜单按钮时,我们需要先判断当前的菜单中是否有该菜单项,如果有直接使用。否则创建新的对象。这里有几个地方需要注意,首先是CommandBarButton 的Tag属性,该属性应该加上一个唯一标志,比如当前时间,或者GUID,然后带上该菜单的名称等信息。加唯一标志的目的是每一次在创建菜单时保证是唯一的,否则会出现菜单只会响应一次按钮点击事件等奇怪的问题。其次设置按钮的Style为MSOffice.MsoButtonStyle.msoButtonIconAndCaption 既带图片又有文字的时候,Picture属性为想要显示在按钮前面的图片,该对象是一个stdole.IPictureDisp类型的对象,您需要进行一下转换。其次直接设置图片会使得图片中的背景色不会透明,背景色为Office的默认风格颜色,如果要将背景色透明,需要设置Mask属性,Mask属性也是一张图片。该图片为带显示图片的蒙版,即原始图片中需要显示的地方,用黑色表示,那么其余地方就会透明显示,具体使用方式您可以参看这篇文章,这里为了简化,不做处理。

添加工具条

工具条其实就是一个大的一级菜单,和创建菜单一样,我们将创建工具条的代码封装到了AddToolBars方法中,该方法代码如下:

public void AddToolBars()
{
    try
    {
        YYToolBar = application.CommandBars["YYToolBar"];
    }
    catch { }

    if (YYToolBar == null)
    {
        YYToolBar = application.CommandBars.Add("YYToolBar", MSOffice.MsoBarPosition.msoBarTop, false, true);
    }
    LoginGroup_ToolBar();
    FinancialGroup_ToolBar();
    MapServiceGroup_ToolBar();
    WeatherReportGroup_ToolBar();
    AboutGroup_ToolBar();

    YYToolBar.Visible = true;
}

我们首先需要创建一个大的工具条,和创建菜单类似,在创建工具条之前,我们需要定义好所有的工具条中的按钮,注意,该按钮对象不能和菜单项里面的对象共用,否则会导致事件注册被冲掉的情况。

//歪歪插件工具条
MSOffice.CommandBar YYToolBar;
//实时行情函数工具条
MSOffice.CommandBarButton btnQuoteFunctionToolBarCommand = null;
//Sina实时行情工具条
MSOffice.CommandBarButton btnQuoteSinaFunctionToolBarCommand = null;
//Yahoo实时行情工具条
MSOffice.CommandBarButton btnQuoteYahooFunctionToolBarCommand = null;

创建好YYToolBar对象后,在该对象的基础上创建工具条里面的工具项就和创建字菜单类似了,这里就不再赘述了。

现在我们来看在Excel2003下面的效果。由于我们创建的SharedAddin程序,我们在调试的时候,需要设置启动程序,Visual Studio 给我们设置的默认启动程序是Visual Studio本身。这里我们将默认程序指定为Excel 2003 的可执行文件,如下图:

SharedAddin Start external programe

运行程序,Visual Studio就会启动Excel程序,然后就可以看到我们创建的歪歪菜单和工具条了。

YYAddinInExcel 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类。如下:

[ComVisible(true)]
public partial class Connect : Office.IRibbonExtensibility
{
    private Office.IRibbonUI ribbon;
    #region IRibbonExtensibility 成员

    public string GetCustomUI(string ribbonID)
    {
        return GetResourceText("YYSharedAddin.RibbonMenu.Ribbon.xml");
    }
    #endregion

    #region 功能区回调
    //在此创建回调方法。有关添加回调方法的详细信息,请在解决方案资源管理器中选择功能区 XML 项,然后按 F1

    public void Ribbon_Load(Office.IRibbonUI ribbonUI)
    {
        this.ribbon = ribbonUI;
    }

    public Image LoadImage(string imageName)
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        //String[] all =assembly.GetManifestResourceNames();//GetResourceName
        Stream stream = assembly.GetManifestResourceStream("YYSharedAddin.Resources." + imageName);
        return Image.FromStream(stream);
    }

    public void GeneralButton_Click(Office.IRibbonControl control)
    {
        try
        {
            MessageBox.Show("you clicked the button id is " + control.Id);
        }
        catch (Exception ex)
        {

        }
    }
    #endregion

    #region 帮助器

    private static string GetResourceText(string resourceName)
    {
        Assembly asm = Assembly.GetExecutingAssembly();
        string[] resourceNames = asm.GetManifestResourceNames();
        for (int i = 0; i < resourceNames.Length; ++i)
        {
            if (string.Compare(resourceName, resourceNames[i], StringComparison.OrdinalIgnoreCase) == 0)
            {
                using (StreamReader resourceReader = new StreamReader(asm.GetManifestResourceStream(resourceNames[i])))
                {
                    if (resourceReader != null)
                    {
                        return resourceReader.ReadToEnd();
                    }
                }
            }
        }
        return null;
    }

    #endregion
}

我们需要注意的是,要设置好正确的资源名称,您可以通过GetManifestResourceNames 来查看该程序集中的所有的资源名称。

现在,将启动项目设置为2007 或者2010版本的Excel,现在菜单又变成Ribbon风格的了:

YY插件菜单

将启动项目设置为2003版本的Excel,菜单就变成传统风格的了。

YYAddinInExcel 2003

四 结语

本文介绍了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菜单系统有所帮助。


<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
中文名: Excel VBA程序开发自学宝典(第2版) 作者: 罗刚君 资源格式: PDF 版本: 扫描版 出版社: 电子工业出版社 书号: 9787121141454 发行时间: 2011年08月01日 地区: 大陆 语言: 简体中文 简介: 内容简介: 《ExcelVBA程序开发自学宝典(第2版)》是VBA入门的经典教材,对VBA的基础理论、语法规则、代码优化、编写思路、开发函数与使用数组等都进行了详尽的理论阐述和案例演示,同时还搭配窗体与控件、正则表达式、字典、FileSystemObject、API、类模块、脚本语言的应用,以及开发功能区、开发加载宏、封装代码等高级应用,力求完整地展示了VBA的功能与魅力。通读本书,您不仅能学到如何开发函数、编写程序,还能设计报表系统,独立开发Excel百宝箱式的大中型插件。   《Excel VBA程序开发自学宝典(第2版)》是畅销书《Excel VBA程序开发自学宝典》的升级版本。《ExcelVBA程序开发自学宝典》第1版于2009年10月上市,基于Excel2007版本撰写,曾多次销罄重印。然而本着精益求精的原则,作者在售后服务QQ群和售后论坛中收集了大量的用户反馈信息,对图书进行改版,删除了部分实用性不大的内容,增加了正则表达式、字典的应用、开发功能区与封装代码等章节,增加了开发插件的案例,全书改用Excel2010截图,并修正了第1版中无法兼容Excel 2010的部分代码与设计思路,促使教学内容更具通用性。 目录: 第1章 从插件看VBA的优越性 1.1 从身份证号获取个人信息 1.1.1 内置公式法 1.1.2 自定义函数法 1.1.3 插件法 1.1.4 浅谈VBA优势 1.2 插件特点及如何发挥插件的优势 1.2.1 Excel插件的特点 1.2.2 Excel插件的优势与限制 1.2.3 如何发挥插件的优势 1.2.4 开发Excel插件的条件 1.2.5 本书架构 第2章 VBA简史与安全性 第3章 巧设VBA编辑器提升编程效率 第4章 VBA基本概念 第5章 深入解析数据类型与变量 第6章 编写Sub过程及开发函数 第7章 对象的引用方式总结 第8章 让代码自动运行 第9章 编程规则与代码优化 第10章 常用语法剖析 第11章 基本编程应用案例 第12章 数组基础 第13章 数组实战 第14章 设计窗体 第15章 表单控件与ActiveX控件 第16章 FSO、WScript与DOS 在VBA中的应用 第17章 正则表达式与VBA 第18章 字典的应用 第19章 命令栏对象与工具栏开发 第20章 自定义菜单 第21章 认识类和类模块 第22章 API的基本应用 第23章 VBA与注册表 第24章 Ribbon功能区设计 第25章 VBE的对象模型与对象控制 第26章 程序开发思想 第27章 开发VBA百宝箱 第28章 插件设计 第29章 代码封装技巧 第30章 开发Excel百宝箱”(本章及附录内容均在光盘中) 附录A Excel 2010的新增事件 附录B Excel 2010对象大全 附录C Excel 2010所有内置常数枚举 附录D 功能区内置命令与图标一览
### 回答1: USB是一种常见的设备连接接口,广泛应用于各种电子产品中。USB系统开发基于ARM Cortex-M3处理器,具有深入浅出的特点。 首先,ARM Cortex-M3是一种高性能,低功耗的处理器架构,特别适用于嵌入式系统和物联网设备。它具有较小的指令集,并且能够以较高的速度执行指令,从而确保了USB系统的高效性能。 在USB系统开发中,我们首先需要了解USB的工作原理和协议。USB分为主机和设备,主机负责控制和管理设备,设备负责提供相应的功能。在ARM Cortex-M3处理器上,我们可以通过编程来实现主机和设备的功能,包括控制传输、中断传输和批量传输等。 其次,USB系统开发需要熟悉USB的架构和规范。USB标准定义了USB设备的各种特性和功能,包括USB传输速率、插座类型、端点数量等。在ARM Cortex-M3处理器上,我们可以通过配置寄存器和使用相关的库函数来实现这些特性。 最后,USB系统开发还需要进行驱动程序的编写和调试。驱动程序是连接设备和操作系统之间的桥梁,通过驱动程序可以实现设备的控制和数据传输。在ARM Cortex-M3处理器上,我们可以使用相关的开发工具来编写USB驱动程序,并通过调试和测试确保其正确性和稳定性。 总之,深入浅出的USB系统开发基于ARM Cortex-M3是一项涉及USB协议、硬件配置和驱动程序开发的复杂任务。通过详细了解USB的工作原理和规范,并利用ARM Cortex-M3处理器的高性能和低功耗特点,可以开发出稳定可靠的USB系统。 ### 回答2: USB系统开发是指在ARM Cortex-M3架构下,开发USB接口及相关功能的系统。USB(Universal Serial Bus)是一种通用的外部接口标准,用于连接计算机和外部设备,实现数据传输和设备控制。 在进行USB系统开发时,需要了解USB接口的硬件设计和软件开发两个方面。硬件设计主要包括电路设计、信号传输和连接接口等。ARM Cortex-M3芯片内置了USB控制器,可以与外部设备进行通信。开发者需要根据系统需求,设计USB接口电路,并将其集成到硬件平台中。 软件开发方面,首先需要了解USB协议标准。USB协议包括设备描述符、配置描述符、端点描述符等,开发者需要根据协议标准来编写相应的代码。其次,需要实现USB的通信功能,包括数据传输和设备控制。这通常需要使用USB设备驱动程序和USB协议栈来完成,以便与计算机进行通信和数据交换。 在ARM Cortex-M3架构下进行USB系统开发,需要使用适当的开发工具和环境。ARM提供了一套完善的开发套件,包括开发板、调试器和IDE等。开发者可以利用这些工具,进行USB系统开发和调试工作。 总之,深入浅出地开发USB系统需要掌握USB接口的硬件设计和软件开发两个方面,并使用相应的开发工具和环境。这样可以实现ARM Cortex-M3芯片与外部设备之间的USB通信和数据传输。 ### 回答3: USB系统开发是指在ARM Cortex-M3处理器上开发和实现USB功能的过程。USB(通用串行总线)是一种常用的外部设备连接接口,它允许将计算机与各种外设连接起来,如键盘、鼠标、打印机等。 在USB系统开发中,首先需要了解USB协议和USB架构。USB协议定义了USB设备与主机之间的通信规则,包括数据传输、速度控制、设备描述等。USB架构包括USB主机、USB设备和USB总线,主机负责控制和管理设备,设备提供特定的功能,总线则提供物理连接。 在ARM Cortex-M3处理器上进行USB系统开发时,需要使用适当的开发工具和软件,如Keil MDK、IAR Embedded Workbench等。首先,要配置处理器的引脚和时钟,以使其能够与USB模块进行通信。然后,需要编写相应的驱动程序来控制USB模块,实现USB的各种功能,如数据传输、中断处理等。 在开发USB系统时,还需要注意以下几点: 1. 确保USB硬件的正确连接和配置,包括连接USB模块的引脚和外部电源。 2. 根据具体需求选择适当的USB模式,如设备模式、主机模式或OTG模式。 3. 编写USB驱动程序,包括初始化USB模块、处理USB中断、处理设备插拔等。 4. 实现USB协议中的各种功能,如设备描述符、配置描述符、端点描述符等。 5. 进行USB设备的功能测试和调试,确保其正常工作。 USB系统开发基于ARM Cortex-M3是一项具有挑战性的任务,需要熟悉USB协议和架构,具备良好的编程能力和调试技巧。通过深入学习和实践,可以掌握USB系统开发的基本原理和方法,为实际应用提供可靠的USB功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值