• (翻译)LearnVSXNow! #14 VSCT文件基础


         在第13篇里,我说过我要给你们展示一些菜单、工具栏和命令的示例代码,但是相关的东西太多了,一篇文章没办法全部囊括,所以在这里我只涉及一些和vsct文件相关的代码。

    前言

         在本系列前面的文章里,我多次提到过Package是按需加载的,IDE只有在真正用到Package的时候才去加载它们。但这样就带来一个问题:IDE如何在不加载Package的情况下,显示Package里定义的菜单和工具栏?或者说当我们在IDE里看到某个Package的菜单的时候,这个Package到底有没有被加载到IDE里?

         当Package被注册后(通过regpkg.exe),Package里代表菜单和工具栏的资源实际上是被单独存放在一个地方,所以在Visual Studio启动后,它就可以从这个地方读取出这个信息,并显示相应的菜单和工具栏,而不必加载Package本身。

         实现这种模式的关键,就在于vsct(Visual Studio Command Table)文件。这个文件是旧版的Visual Studio SDK中ctc文件的替代品,是用来定义命令以及与命令相关的UI的。编译完package后,vsct文件被编译到一个cto文件中,并且作为一个资源添加到package的dll里。

         在VS 2005版本的Visual Studio SDK里,用的是文本格式的ctc文件。编辑和理解ctc文件并不是一个简单的任务。所以在Visual Studio 2008 SDK里,微软创建了一种新的基于xml的vsct文件和相应的编译器,负责把vsct编译成cto格式。

         应用vsct文件的最大的优势在于它就是一个xml文件,它拥有xml文件固有的特性,例如自动生成结束标签或者智能感知。所以微软建议我们用vsct文件来代替ctc文件,当然,ctc文件目前依然可以使用。

         在这篇文章里,我将给大家介绍一些在前面的文章里没有提到的关于vsct文件的细节。首先我要先介绍一下vsct文件的基础,然后再用一些例子来说明它。

    VSCT文件的结构

         xml文件的xsd架构可以告诉我们一个xml文件里应该包含什么内容,因为xsd文件里定义了相应的xml文件的语法、词法等很多信息,并且“据说”不管是对计算机还是对人来说,可读性都很好。毫无疑问,计算机可以很牛逼的识别xsd文件,但对于我们人类来说,其实它的可读性并不是那么好。所以在这里我就不给大家展示vsct的xsd架构了,而是通过例子来解释一下vsct的结构。

     

    外层节点

        VSCT文件的根结点是CommandTable

    <?xml version="1.0" encoding="utf-8"?>
    <CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/..." 
      xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <!-- Content of the command table -->
    </CommandTable>

         command table的元素的命名空间是“http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable”,不要忘了加上它,但是我为了使示例代码更短,所以不加这个命名空间。

         CommandTable的子节点是:
    <CommandTable xmlns="..." xmlns:xs="...">
      <Extern/>
      <Include/>
      <Define/>
      <Commands/>
      <CommandPlacements>
      <VisibilityConstraints/>
      <KeyBindings/>
      <UsedCommands/>
      <Symbols/>
    </CommandTable>

         其中,最重要的是Extern、Commands和Symbols节点,让我们看一下VSPackage向导帮我们生成的vsct文件:

    <?xml version="1.0" encoding="utf-8"?>
    <CommandTable xmlns="..." xmlns:xs="...">
      <Extern href="stdidcmd.h" mce_href="stdidcmd.h"/>
      <Extern href="vsshlids.h" mce_href="vsshlids.h"/>
      <Extern href="msobtnid.h" mce_href="msobtnid.h"/>  
     
      <Commands package="guidSimpleCommandPkg">
        <Groups>
          <Group guid="guidSimpleCommandCmdSet" id="MyMenuGroup" priority="0x0600">
            <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
          </Group>
        </Groups>
      
        <Buttons>
          <Button guid="guidSimpleCommandCmdSet" id="cmdidMyFirstCommand" 
            priority="0x0100" type="Button">
            <Parent guid="guidSimpleCommandCmdSet" id="MyMenuGroup" />
            <Icon guid="guidImages" id="bmpPic1" />
            <Strings>
              <CommandName>cmdidMyFirstCommand</CommandName>
              <ButtonText>My First Command</ButtonText>
            </Strings>
          </Button>
        </Buttons>
        <Bitmaps>
          <Bitmap guid="guidImages" href="Resources\Images_32bit.bmp" mce_href="Resources\Images_32bit.bmp" 
            usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/>
        </Bitmaps>
      </Commands>
      
      <Symbols>
        <GuidSymbol name="guidSimpleCommandPkg" 
          value="{2291da24-92e5-4ea4-bdb7-72a9b5ac7d59}" />
        <GuidSymbol name="guidSimpleCommandCmdSet" 
          value="{a982b107-4ad4-437e-b2bc-cdf2708aa376}">
          <IDSymbol name="MyMenuGroup" value="0x1020" />
          <IDSymbol name="cmdidMyFirstCommand" value="0x0100" />
        </GuidSymbol>
        <GuidSymbol name="guidImages" value="{5c3faf04-8190-48c4-a6e9-71f04f1848e5}" >
          <IDSymbol name="bmpPic1" value="1" />
          <IDSymbol name="bmpPic2" value="2" />
          <IDSymbol name="bmpPicSearch" value="3" />
          <IDSymbol name="bmpPicX" value="4" />
          <IDSymbol name="bmpPicArrows" value="5" />
        </GuidSymbol>
      </Symbols>  
    </CommandTable>

    Symbols和IDs

         我在第6篇里已经说过了,VS IDE里的对象(例如命令和相关的UI元素)都有唯一的标识,我们需要利用他们的唯一标识符来引用某个元素。标识符由一个GUID和一个32位无符号整数组成。GUID代表一个逻辑上包含对象的容器,32位无符号整数代表这个对象在逻辑容器内的id。(也有一些对象只用GUID来标识,稍后我会介绍它们)。

         在vsct文件里,如果直接用这些GUID和ID的话,代码的可读性就太差了,幸好vsct文件里有Symbols节点。该节点用于给这些GUID或者ID起个可读性较好的名字,其中:GuidSysmbol子节点用来给逻辑容器GUID起别名,嵌套的IDSymbol节点用来给32位无符号数起别名。

         在上面的代码段中,定义了三个GUID容器。第一个是一个空的容器(别名是guidSimpleCommandPkg),另外两个则包含若干个ID。定义好了symbols之后,就可以引用它们了:

    <Commands package="guidSimpleCommandPkg">
        <Groups>
          <Group guid="guidSimpleCommandCmdSet" id="MyMenuGroup" priority="0x0600">
            <!-- ... --> 
          </Group>
        </Groups>
      
        <Buttons>
          <Button guid="guidSimpleCommandCmdSet" id="cmdidMyFirstCommand" 
            priority="0x0100" type="Button">
            <!-- ... -->
          </Button>
        </Buttons>   
     
        <Bitmaps>
          <Bitmap guid="guidImages" href="Resources\Images_32bit.bmp" mce_href="Resources\Images_32bit.bmp" 
            usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/>
        </Bitmaps>
      </Commands>
     

         在定义命令的时候,我们经常需要引用VS IDE里已经定义好的菜单。例如,如果想在“工具”菜单下添加子菜单,我们必须引用已经定义在VS IDE里的“工具”这个菜单。当然, “工具”菜单和其他菜单(包括我们自己的菜单)的定义方式是一样的:

    <Group guid="guidSimpleCommandCmdSet" id="MyMenuGroup" priority="0x0600">
      <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
    </Group>

         Parent子节点指定了由Group元素定义的逻辑容器应该被放在哪个位置。guidSHLMainMenu 代表VS IDE的主菜单的逻辑容器,IDM_VS_MENU_TOOLS 表示“工具”菜单项的ID。也许你已经猜到了,有上千个和VS IDE相关的GUID和ID。

         可以用Extern节点来访问它们:

    <?xml version="1.0" encoding="utf-8"?>
    <CommandTable xmlns="..." xmlns:xs="...">
      <Extern href="stdidcmd.h" mce_href="stdidcmd.h"/>
      <Extern href="vsshlids.h" mce_href="vsshlids.h"/>
      <Extern href="msobtnid.h" mce_href="msobtnid.h"/>
      <!-- ... -->
    </CommandTable>

         Extern节点用于引用已经定义好的GUID和ID。.h文件是标准的c++头文件,里面定义了很多标识符和宏,把这些头文件引用进来之后,就可以在vsct文件的任何地方引用已经定义好的GUID和ID了,就像我们定义在Symbols节点里的一样。

         这些头文件位于VS 2008 SDK根目录的VisualStudioIntegration\Common\Inc子目录下面:

    文件 内容
    stdidcmd.h

    包含Visual Studio里公开的所有命令的ID。其中,用于菜单命令的ID用cmdid作为前缀,用于标准编辑器命令的ID用ECMD_prefix作为前缀,还包括一些其他的命令ID

    vsshlids.h

    包含Visual Studio Shell的菜单命令的ID

    msobtnid.h

    包含标准的Microsoft Office命令(其中很多命令用在VS IDE里,例如剪切、复制、粘贴)

         如果你有耐心看一下这几个文件的话,你就会在vsshlids.h文件里找到guidSHLMainMenuIDM_VS_MENU_TOOLS的定义:

    ...
    DEFINE_GUID (guidSHLMainMenu,
      0xd309f791, 0x903f, 0x11d0, 0x9e, 0xfc, 0x00, 0xa0, 0xc9, 0x11, 0x00, 0x4f);
    ...
    #define IDM_VS_MENU_TOOLS 0x0085
    ...

    Commands

         毫无疑问,vsct文件里最重要的节点就是Commands了。这个节点用来定义命令:

    <Commands package="...">
      <Groups/>
      <Menus/>
      <Buttons/>
      <Combos/>
      <Bitmaps/>
    </Commands>

         任何一个命令都必须从属于IDE本身或者从属于某个Package。一个程序集可以包括一个或多个Package,为了指定Command所在的Package,Commands节点的package属性必须是相应package的GUID。通常情况下,我们的程序集里只包含一个Package,所以我们通常在把VSPackage向导帮我们生成的Package的ID作为package属性的值:

    <Commands package="guidSimpleCommandPkg">
      <!-- ... -->
    </Commands>

         Commands节点下包含一些子节点,每一个都有自己的功能:

    Groups

         在Groups下,用子节点Group元素来定义所谓的命令组。一个命令组是一个逻辑容器,里面包含了功能相近的命令。例如,“生成解决方案”、“重新生成解决方案”和“清理解决方案”这几个菜单属于同一个组:它们位于VS主菜单的“生成”菜单下面,或者某个解决方案的右键菜单中:

    image image

         我们并不是把单独的命令直接放到一个已经存在的菜单下面,而是把一个命令组放进去。属于这个组中的每个命令都会显示在相关的菜单下面,命令组可以看做是重用命令的一种方式。

    Menus

         在Menus下,用Menu子节点定义菜单,菜单有多种表现形式,最常用的有:

    1. 标准菜单:例如VS IDE中的文件、编辑、视图菜单。
    2. 上下文菜单:当在某些对象上点击鼠标右键时,弹出上下文菜单。
    3. 工具条:多个命令可以放在一行里。

    Buttons

         在Buttons节点里可以定义多个Button节点,一个Button代表用户可以交互的一个UI。不过,“Button”这个名字很容易让我们误解,因为我们通常所说的“Button”代表的是在表单上可以点击的按钮。但是在这里,“Button”的含义更像是一个菜单项。在vsct文件里,我们可以定义几种类型的Button:

    1. 标准按钮:用来执行命令的菜单项。
    2. 菜单按钮:用来显示子菜单。
    3. 下拉按钮:例如VS IDE里的Undo和Redo。
    4. “Swatch”按钮:用于显示像字体颜色选择器之类的按钮。

    Combos

         Combos节点下可以定义多个Combo节点。一个Combo节点用于显示在Combo box里的命令。我认为理解这个需要一定的vsx基础,所以我会在晚些时候再来说明这个概念。在我写这篇文章的时候,VSCT的文档里有一个小错误:它里面说到Combo节点是Commands节点的直接子节点,但实际上正确的结构是Commands、Combos和Combo。所幸,vsct的智能提示是正确的。

    Bitmaps

         工具条和菜单如果没有图标的话,对用户来说就太索然无味了。Bitmaps节点就是用来定义图标的。图片可以来自于外部文件或者package的资源文件。

         可以用多种格式的图片,例如bmp、gif、png。但是对于这几种图片来说,不能用同一种使用方式。例如,我在用32位bmp图片的时候遇到了问题,如果在显示设置里用了120DPI的话,原本16*16像素的图片会被拉伸成20*20的,在拉伸后的图片里自动添加了一些带颜色的像素;但是如果用png图片的好,拉伸后的图片看起来就很圆滑。在某些情况下只有特定格式的图片才能被支持(我不清楚这到底是一个bug还是vs的特性):例如对于工具窗的图标来说,png图片是不支持的(如果用了png,并不会显示图标),只支持24位的以紫红色作为透明色的bmp图片。

         所以,如果在用图标时遇到了问题了,不妨换几种图片格式试试看。

     

    定义Command

         为了成功的在VS IDE里添加命令,我们至少需要一个Group和一个Button节点,如果我们还想添加图标的话,我们还需要至少一个Bitmap节点。如果我们不想简单的把命令组添加到VS已经定义好的菜单下的话,我们还需要Menu节点。

         MenuGroupButton节点有一些共有的属性和子节点。下表是这些属性:

    属性 描述
    guid

    元素标识符的GUID部分,必填。

    id

    元素标识符的uint部分,必填。

    priority

    表示元素排列顺序的数字,可选项。数字越小,位置越靠前。但是我们并不知道所有元素的priority的值,所以用这个属性并不能保证可以精确的排列元素。

    type

    确定元素的外观和布局的可选项,但Group节点不包含这个属性。

         除了Bitmap之外,Commands的其他子节点都有如下的子节点:

    子节点 描述
    Parent

    该元素的上级。在第13篇文章里我提到过一个命令可以附加到一个或多个菜单项上。在这里你可以定义0个或1个Parent元素。如果想把一个命令附加到一个以上的菜单时,可以用

    CommandPlacement元素(稍后我们会提到)。

    Parent元素用guid和id属性来标识上级元素。对于Button来说,它的Parent必须是Group;对于Group来说,它的Parent必须是Menu。

    Annotation

    添加注释,可选项。注释可以是简单的文本,也可以是嵌套的结构。

     

         MenuButtonCombo的子节点如下:

    子节点 描述
    CommandFlag

    可以包含0个或多个该节点。某些标记只有和特定的标记联合起来使用时才有效,例如,

    DynamicVisibilityDefaultInvisible两个标记表示在vs启动的时候,对应的菜单项不显示。

    Strings

    这个节点包括几个子节点,表示对应元素的文本。至少需要包括一个ButtonText子节点,用于定义对应元素的文本标题。另外,还可以有ToolTipTextMenuTextCommandName以及其他子节点。更多细节可以参考vsct的schema。

    Icon

    只有Button元素才能包含该子节点,用于定义和Button相关的图标。

    定义Bitmap

         Commands节点下的Bitmaps节点用来定义菜单和工具条项中用到的图片。每一个图片用一个Bitmap元素定义。Bitmap元素里引用一个16*16像素的图片,或者一个16*N的bitmap strip,其中N是16的倍数。一个bitmap由一个GUID标识,但这个GUID并不是package的ID,也不是command set的ID。我们用基于1的数字来指定bitmap strip中的一个特定图片。

         像command和menu的ID一样,我们也在Symbols里面定义bitmap的ID。例如,如果我们用VSPackage向导创建了一个带有工具窗的package的话,在vsct文件里我们可以看到如下定义:

    <?xml version="1.0" encoding="utf-8"?>
    <CommandTable xmlns="..." xmlns:xs="...">
      <!-- Extern elements -->
      <Commands package="...">
        <!-- Menus, Groups and Buttons -->
        <Bitmaps>
          <Bitmap guid="guidImages" href="Resources\Images_32bit.bmp" mce_href="Resources\Images_32bit.bmp"
            usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/>
        </Bitmaps>
      </Commands>
      <Symbols>
        <GuidSymbol name="guidImages" value="{...}" >
          <IDSymbol name="bmpPic1" value="1" />
          <IDSymbol name="bmpPic2" value="2" />
          <IDSymbol name="bmpPicSearch" value="3" />
          <IDSymbol name="bmpPicX" value="4" />
          <IDSymbol name="bmpPicArrows" value="5" />
        </GuidSymbol>
      </Symbols>
    </CommandTable>

         在Symbols节点下定义了Bitmap专用的GUID(guidImages),并且也用基于1的数字定义了图片在bitmap strip中的索引。在上面这个例子里,bmpPicSearch是strip中的第3个图片。

         Bitmaphref属性指定了图片文件的位置,是相对于vsct文件的位置。usedList属性指定bitmap strip里可用的图片。如果我们想把一个Button的图标设置成第三个图片,我们可以用下面的代码:

    <Button ...>
      <Icon guid="guidImages" id="bmpPicSearch" > 
    </Button>

    创建菜单的一些例子

         在讨论了vsct的Groups、Menus和Buttons之后,让我们来看一些例子。

     

    创建一个主菜单级别的命令

         VSPackage向导可以帮我们把菜单放到如下位置:如果我们创建一个简单的命令的话,向导会把菜单放到“工具”菜单下;如果我们创建一个简单的工具窗的话,向导会把菜单放到“视图”菜单下。然而,在很多情况下我们需要把菜单放到VS的主菜单里。该怎么做呢?

         现在我们要在vs的主菜单上添加一个“HowToPackage”的菜单,并且包含两个菜单命令。我们需要按照下面的步骤来做:

    1. 第一步:在Symbols节点下,添加一个GuidSymbol节点,在这里定义我们需要用到的符号。
    2. 第二步:在Menus节点下,添加一个Menu节点,用来定义显示在主菜单里的菜单,并把它的Parent设置成一个主菜单级别的Group。
    3. 第三步:在Groups节点下,添加一个Group节点,用来定义我们的两个菜单命令的组。并把Parent设置成第二步里添加的Menu的id。
    4. 第四步:在Buttons节点下,添加两个Button节点,用于定义这两个命令。并且把Parent设置成第三步里添加的Group的id。

         对应的vsct文件的内容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <CommandTable xmlns="..." xmlns:xs="...">
      <Extern href="stdidcmd.h" mce_href="stdidcmd.h"/>
      <Extern href="vsshlids.h" mce_href="vsshlids.h"/>
      <Extern href="msobtnid.h" mce_href="msobtnid.h"/>
      <Commands package="...">
        <Menus>
          <Menu guid="guidHowToPackageCmdSet" id="TopLevelMenu" priority="0x100" 
            type="Menu">
            <Parent guid="guidSHLMainMenu" id="IDG_VS_MM_BUILDDEBUGRUN" />
            <Strings>
              <ButtonText>HowToPackage</ButtonText>
              <CommandName>HowToPackage</CommandName>
            </Strings>
          </Menu>
        </Menus>
      
        <Groups>
          <Group guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup" 
            priority="0x0600">
            <Parent guid="guidHowToPackageCmdSet" id="TopLevelMenu"/>
          </Group>
        </Groups>    
     
        <Buttons>
          <Button guid="guidHowToPackageCmdSet" id="cmdFirstCommand" priority="0x0100" 
            type="Button">
            <Parent guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup" />
            <Strings>
              <CommandName>cmdidFirstCommand</CommandName>
              <ButtonText>First Command</ButtonText>
            </Strings>
          </Button>
          <Button guid="guidHowToPackageCmdSet" id="cmdSecondCommand" 
            priority="0x0101" type="Button">
            <Parent guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup" />
            <Strings>
              <CommandName>cmdidSecondCommand</CommandName>
              <ButtonText>Second Command</ButtonText>
            </Strings>
          </Button>
        </Buttons>  
      </Commands>
      
      <Symbols>
        <GuidSymbol name="guidHowToPackageCmdSet" 
          value="{8D7B9CB3-3591-47f9-B104-B7EB173E0F03}" >
          <IDSymbol name="TopLevelMenu" value="0x0100" />
          <IDSymbol name="TopLevelMenuGroup" value="0x0200" />
          <IDSymbol name="cmdFirstCommand" value="0x0300" />
          <IDSymbol name="cmdSecondCommand" value="0x0301" />
        </GuidSymbol>
        <!-- Other Guids for the package -->
      </Symbols>  
    </CommandTable>
     

         正如你看到的那样,为了实现这个简单的功能,我们写了好多代码。在菜单的定义那里,我把Parent里用到的ID高亮显示了。如果运行起这个Package,会看到在“生成”和“调试”菜单中间,多了一个新的菜单:

    image 

         这是由Menu的Parent属性和priority属性决定的:

    <Menu guid="guidHowToPackageCmdSet" id="TopLevelMenu" priority="0x100"   
      type="Menu">
      <Parent guid="guidSHLMainMenu" id="IDG_VS_MM_BUILDDEBUGRUN" />
      <!-- ... -->
    </Menu>

         IDG_VS_MM_BUILDDEBUGRUN是包含“生成”和“调试”菜单的逻辑组,priority属性值0x100使我们的菜单显示在“调试”之前。如果把priority的值改成0x700的话,我们的菜单就会移到“调试”菜单的后面:

    image

     

         在看到Button定义的代码之后,你也许会觉得Group的存在并不必要:为什么不把Button的Parent直接设置成Menu呢:

    <Button ...>
      <Parent guid="guidHowToPackageCmdSet" id="TopLevelMenu" />
      <!-- ... -->
    </Button>

         把Button的定义改了以后,会发现HowToPackage菜单消失了。这是因为button的parent不能直接是menu,它的parent必须是group才行。正是由于HowToPackage菜单没有任何子菜单,所以它不显示了。

    在一个菜单里分隔菜单命令

         如果我们在一个菜单下放一个以上的group,vs会在group直接插入一个分隔符。现在让我们在上面已经创建的vsct文件里再添加一个含有两个命令的group:

    1. 第一步:为新的group和button添加新的Symbols。
    2. 第二步:添加一个新的Group。
    3. 第三步:添加两个新的Button。
         修改后的vsct文件如下:
    <?xml version="1.0" encoding="utf-8"?>
    <CommandTable xmlns="..." xmlns:xs="...">
      <!-- Extern elements -->
      <Commands package="...">
        <!-- Menus section unchanged -->  
        <Groups>
          <!-- New group added -->
          <Group guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup2" 
            priority="0x0600">
            <Parent guid="guidHowToPackageCmdSet" id="TopLevelMenu"/>
          </Group>
        </Groups>  
     
        <Buttons>
          <!-- New buttons added -->
          <Button guid="guidHowToPackageCmdSet" id="cmdThirdCommand" priority="0x0102"
            type="Button">
            <Parent guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup2" />
            <Strings>
              <CommandName>cmdidThirdCommand</CommandName>
              <ButtonText>Third Command</ButtonText>
            </Strings>
          </Button>
          <Button guid="guidHowToPackageCmdSet" id="cmdFourthCommand" 
            priority="0x0102" type="Button">
            <Parent guid="guidHowToPackageCmdSet" id="TopLevelMenuGroup2" />
            <Strings>
              <CommandName>cmdidFourthCommand</CommandName>
              <ButtonText>Fourth Command</ButtonText>
            </Strings>
          </Button>
        </Buttons>
      </Commands>
      
      <Symbols>
     
        <GuidSymbol name="guidHowToPackageCmdSet" value="{...}" >
          <!-- New IDSymbols added -->
          <IDSymbol name="TopLevelMenuGroup2" value="0x0201" />
          <IDSymbol name="cmdThirdCommand" value="0x0302" />
          <IDSymbol name="cmdFourthCommand" value="0x0303" />
        </GuidSymbol>
        <!-- Other Guids for the package -->
      </Symbols>  
    </CommandTable>

         运行起来后的效果如下图:

    image

    为菜单添加图标

         如果我们想给菜单添加图标,我们需要定义个Bitmap节点,并且给Button节点添加相应的Icon属性:

    1. 第一步:为Bitmap strip添加一个ID。
    2. 第二步:添加Bitmap节点,并且设置可用的图片。
    3. 第三步:为Button添加Icon属性。

         修改后的vsct文件如下:

    <?xml version="1.0" encoding="utf-8"?>
    <CommandTable xmlns="..." xmlns:xs="...">
      <!-- Extern elements -->
      <Commands package="...">
        <!-- Menus section unchanged -->
        <!-- Groups section unchanged -->
        <Buttons>
          <Button guid="guidHowToPackageCmdSet" id="cmdFirstCommand" priority="0x0100" 
            type="Button">
            <!-- Icon added, other children unchanged -->
            <Icon guid="guidImages" id="bmpPic1" />
          </Button>
          <Button guid="guidHowToPackageCmdSet" id="cmdSecondCommand" 
            priority="0x0101" type="Button">
            <!-- Icon added, other children unchanged -->
            <Icon guid="guidImages" id="bmpPic2" />
          </Button>
          <Button guid="guidHowToPackageCmdSet" id="cmdThirdCommand" priority="0x0102" 
            type="Button">
            <!-- Icon added, other children unchanged -->
            <Icon guid="guidImages" id="bmpPicX" />
          </Button>
          <Button guid="guidHowToPackageCmdSet" id="cmdFourthCommand" 
            priority="0x0102" type="Button">
            <!-- Icon added, other children unchanged -->
            <Icon guid="guidImages" id="bmpPicArrows" />
          </Button>
        </Buttons>
      
        <Bitmaps>
     
          <!-- A new Bitmap added -->
          <Bitmap guid="guidImages" href="Resources\Images_24bit.bmp" 
            usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/>
        </Bitmaps>
      </Commands>
      
      <Symbols>
        <!-- New GuidSymbol section added -->
        <GuidSymbol name="guidImages" value="{...}" >
          <IDSymbol name="bmpPic1" value="1" />
          <IDSymbol name="bmpPic2" value="2" />
          <IDSymbol name="bmpPicSearch" value="3" />
          <IDSymbol name="bmpPicX" value="4" />
          <IDSymbol name="bmpPicArrows" value="5" />
        </GuidSymbol>
        <!-- Other Guids for the package -->
      </Symbols>  
    </CommandTable>
     

         运行后的效果如下图:

    image

     

    试一下CommandFlag

         CommandFlag节点可以定义命令的一些行为。让我们看一个简单的例子:为第一个命令添加TextOnly标记,为第三个命令添加DefaultDisabled 标记:

    <Buttons>
      <Button guid="guidHowToPackageCmdSet" id="cmdFirstCommand" priority="0x0100" 
        type="Button">
        <!-- CommandFlag added, other children unchanged -->
        <CommandFlag>TextOnly</CommandFlag>
      </Button>
      <Button guid="guidHowToPackageCmdSet" id="cmdThirdCommand" priority="0x0102" 
        type="Button">
        <!-- CommandFlag added, other children unchanged -->
        <CommandFlag>DefaultDisabled</CommandFlag>
      </Button>

         运行后的效果如下图:

    image

     

    小结

         在这篇文章里,我们围绕着vsct文件谈论了Visual Studio的Command table。在生成VSPackage时,vsct文件被编译到cto文件里,并且作为嵌入的资源添加到Package程序集里。通过regpkg.exe注册到VS里之后,VS就知道在启动时应该加载哪些菜单项了。

         vsct文件是旧版的ctc文件的替代品,在这个文件里,最重要的部分是Commands节点,在这个节点里可以定义命令以及相关的Menu、Group、Button、Combo和Bitmap元素。IDs定义在Symbols节点里。利用Extern元素,我们可以引用VS预定义的头文件。

         在这篇文章的第二部分,我们用几个例子来说明如何定义vsct文件。

         但这仅仅是个开始。

    原文链接:http://dotneteers.net/blogs/divedeeper/archive/2008/03/02/LearnVSXNowPart14.aspx

    写在后面的话:

         离上一篇本系列的翻译已经过了很长时间了,在这里要和各位关注vsx的同学说声对不起。由于本人水平有限,翻译一篇实在太耗费时间和精力了,再加上最近比较忙,所以这个系列的进度很慢。还望各位在理解的同时,多多支持,您的支持就是我继续下去的动力。

  • 相关阅读:
    fiddler 抓取 安卓模拟器 https包
    heidiSQL使用简介
    weblogic重启脚本
    svn命令在linux下的使用
    LVS之NAT和DR服务脚本
    LVS之NAT模型、DR模型配置和持久连接
    apache ab压力测试报错apr_socket_recv
    LVS负载均衡模型及算法概述
    Orcale11g单机安装与卸载
    IPC相关的命令
  • 原文地址:https://www.cnblogs.com/default/p/1766451.html
Copyright © 2020-2023  润新知