随笔-56  评论-341  文章-0 

(翻译)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的同学说声对不起。由于本人水平有限,翻译一篇实在太耗费时间和精力了,再加上最近比较忙,所以这个系列的进度很慢。还望各位在理解的同时,多多支持,您的支持就是我继续下去的动力。

posted on 2010-06-28 08:18 明年我18 阅读(...) 评论(...) 编辑 收藏