现在的位置: 首页 > 综合 > 正文

(翻译)LearnVSXNow!-#6 创建我们第一个工具集-序幕

2011年04月21日 ⁄ 综合 ⁄ 共 6375字 ⁄ 字号 评论关闭

     在前面的文章中,我们在向导的帮助下创建了一些小的VSPackages。在第五讲中我们整理了VSX的一些思路和概念,深入了解了packages是如何工作的以及服务的机制。在这篇文章中我们继续前进。

      为了创建创建“容易编写和理解”的代码,从本文开始,我们开始创建一个工具集示例Package。我计划用至少如下三个主题来讨论:

  1. 序幕:创建示例package的第一部分,它是这个工具集的基础。在这篇中我们将手动添加菜单命令来探讨一下command table configuration文件。
  2. 完成示例:在这篇文章里,我们创建示例package的第二部分。手动添加一个自定义Tool Window,并且探索一下output window。
  3. 重构:我们修改package,提取一些在package开发中公共的可复用的类型。

      在这个系列中,我们会创建一个工具窗,它可以对两个整数进行算术运算。

image

     写这个系列的目的,并不是为了实现这个工具集的功能,而是为了熟悉创建类似应用的步骤。通过创建这个简单的工具集,可以使我们更熟悉package的开发,这要比直接讲解VS SDK中的interop程序集和MPF类更容易理解。

创建一个空的VSPackage

     我们先创建一个空的VSPackage。因为在前面的文章中我说明了创建空package的步骤,所以在这里就省略掉截图了。选择Visual Studio Integration Package类型的项目,该项目模板会弹出我们的朋友—VSPackage向导。命名工程为StartupToolset。选择C#语言,根据下面的图片填写基本的信息:

image

     在下一个向导页面不要勾选Menu command, Tool window 和 Command editor中的任何一个(因为我们要手动添加它们);再下一步也不要勾选任何测试项目,最后点击完成。向导生成了一个空package的项目。运行后检查Help|About对话框,以确认StartupToolset包是否在VS实验室环境下被正确的注册了。(注意:为了减少代码量和提高可读性,这个时候我删除了向导生成的注释,你当然也可以这么做,但这些注释有利于理解代码的含义,很值得一读)

     在前面的文章中我们通过向导添加了菜单命令和工具窗口。在这个例子中我们将手动添加。

手动添加新的菜单项

     为了显示一个菜单项,我们要这样做:

  1. 为命令创建一个ID、名字和显示的文本,该命令用于显示tool window
  2. 创建.vsct文件来设置所谓的command table configuration
  3. 为package类添加ProvideMenuAttribute
  4. 设置.vsct文件的Build Action
  5. 创建菜单项的事件处理函数
  6. 建立命令和该事件处理函数的关联

什么是command table configuration文件?

     在之前的文章中,我提到过VSPackages是“按需加载(on-demand loaded)”的,当packages中的对象将要被创建,或者其中的服务将要被使用的时候IDE才将他们装载进内存。这听起来不错,不过有个问题:如果对象表示了菜单或者工具栏对象,并且和package的源代码编译在一起,那么IDE不得不仅仅为了展示这些UI而加载这个package,哪怕这个package并没有被使用。为了显示这些跟package相关的菜单和工具栏(而避免上述情况的发生),这些对象被设计成package的二进制资源。当package被注册(通过regpkg.exe)时,这些资源被提取并分开存放,这样Visual Studio就可以在不加载package的情况下显示这些资源。

     command table configuration文件是要实现这个策略的关键。这个文件的职责是定义与命令相关的UI元素。当我们编译一个package时,command table configuration文件转换成一个cto文件(command table output file),并作为一个资源,编译到package中。

     在vs2005版本的VS SDK中,使用一种文本形式的command table configuration文件(.ctc后缀)。理解和编辑.ctc文件不是件容易的事。随着Visual Studio 2008 SDK的发布,微软创建了一种基于XML的文件格式(.vsct: Visual Studio Command Table),并且配以一种新的编译器(VSCTCompile)来将.vsct文件编译成.cto文件。

     vsct文件主要的优点是它像其他xml文件一样,很容易编辑,并且沿袭了XML所有的好的特性,比如自动生成结束标签和基于vsct XML 架构的智能感知。尽管仍然可以使用ctc文件,但微软推荐使用vsct文件。

第一步:增加一个command ID

     为Command指定ID的目的,是为了将这个package里的命令项和Visual Studio中的命令项或其他package中的加以区分。Command是以ID作为标识的UI相关的对象,就像菜单项或者bitmaps那样。UI相关对象的ID是分层次的,由一个GUID和32位无符号整数组成。GUID表示逻辑上拥有这些UI对象的容器,而32位无符号数则用来在容器内部区分不同的对象。

     向导生成的Guids.cs文件包含了一个用于标识package的GUID和一个用于标识命令集(command set)的GUID:

   1: using System; 

   2: namespace MyCompany.StartupToolset

   3: { 

   4:       static class GuidList 

   5:       { 

   6:             public const string guidStartupToolsetPkgString = "1376bfe2-5278-493d-867e-2b5ba828368d"; 

   7:             public const string guidStartupToolsetCmdSetString = "ec3d3ea6-2261-4a18-a458-78591688e06d"; 

   8:             public static readonly Guid guidStartupToolsetCmdSet = new Guid(guidStartupToolsetCmdSetString); 

   9:       } 

  10: }

     我们要显示的菜单项是从属于command set容器中的一个对象,所以我们还需要在command set容器内部,用一个32位无符号数来标识我们的菜单项。我们把这个ID作为一个常量放在一个新的文件PkgCmdID.cs中(这个文件名的命名是根据惯例来命名的,如果在向导中勾选了Menu Command的话,向导也会生成这么一个文件)

     新建一个PkgCmdID.cs并写入如下代码:

   1: using System; 

   2: using System.Collections.Generic; 

   3: using System.Linq; 

   4: using System.Text; 

   5: namespace MyCompany.StartupToolset 

   6: { 

   7:       static class PkgCmdIDList 

   8:       { 

   9:             public const uint cmdidCalculateTool = 0x101; 

  10:       } 

  11: } 

第二步:建立.vsct文件

     vsct文件用来定义command table configuration,它是XML格式的。为了显示一个菜单项,我们必须创建一个vsct文件,定义用户对象和所需的资源,并且与代码绑定以实现相关的行为。在以后的文章中,我会非常详细地解释vsct文件的格式和用法,但这一次我们只是简单的看一下它。

     因为我们创建的是一个空的package,所以向导没有创建任何command table文件,我们需要手动添加一个StartupToolset.vsct文件。在“添加新项”对话框中选择XML文件,并命名为StartupToolset.vsct,写入如下代码:

   1: <?xmlversion="1.0" encoding="utf-8"?> 

   2: <CommandTable xmlns= 

   3:       "http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" 

   4:       xmlns:xs="http://www.w3.org/2001/XMLSchema"> 

   5:       <Extern href="stdidcmd.h"/> 

   6:       <Extern href="vsshlids.h"/> 

   7:       <Extern href="msobtnid.h"/> 

   8:       <Commands package="guidStartupToolsetPkg"> 

   9:             <Buttons> 

  10:                   <Button guid="guidStartupToolsetCmdSet" id="cmdidCalculateTool" 

  11:                         priority="0x0100" type="Button"> 

  12:                         <Parent guid="guidSHLMainMenu" id="IDG_VS_WNDO_OTRWNDWS1"/> 

  13:                         <Icon guid="guidImage" id="bmpPic1"/> 

  14:                         <Strings> 

  15:                               <CommandName>cmdidCalculateTool</CommandName> 

  16:                               <ButtonText>Calculate Tool Window</ButtonText> 

  17:                         </Strings> 

  18:                   </Button> 

  19:             </Buttons> 

  20:             <Bitmaps> 

  21:                   <Bitmap guid="guidImage" href="Resources\Clock.bmp" usedList="bmpPic1"/> 

  22:             </Bitmaps> 

  23:       </Commands> 

  24:       <Symbols> 

  25:             <GuidSymbol name="guidStartupToolsetPkg" 

  26:                   value="{1376bfe2-5278-493d-867e-2b5ba828368d}"/> 

  27:             <GuidSymbol name="guidStartupToolsetCmdSet" 

  28:                   value="{ec3d3ea6-2261-4a18-a458-78591688e06d}"> 

  29:                   <IDSymbol name="cmdidCalculateTool" value="0x0101"/> 

  30:             </GuidSymbol> 

  31:             <GuidSymbol name="guidImage" value="{91CB158E-29BC-4818-8C1F-967AF94D96B1}">

  32:                   <IDSymbol name="bmpPic1" value="1"/> 

  33:             </GuidSymbol> 

  34:       </Symbols> 

  35: </CommandTable>

(译者注:作者并没有说明图片资源“Clock.bmp”是怎样做出来的,读者可以从之前的示例项目(例如SimpleToolWindow项目)中复制一个图片(如Images_32bit.bmp)过来)

     .vsct文件的根元素是CommandTable,指定了名字空间和XML架构。

     我之前提到过,对象的标识是由GUID和<GUID,数字>对来定义的。在CommandTable中我们必须涉及到在Visual Studio中使用的对象标识,Extern元素允许从外部文件(头文件)加载这些ID。在这个CommandTable中我们使用了如下头文件:

文件 内容

stdidcmd.h

这个文件包含了Visual Studio公开的所有命令的ID。可见的(和不可见的)菜单项的ID以cmdid 开头,标准编辑器命令以ECMD_ 开头等。

vsshlids.h

这个文件包括了Visual Studio外壳提供的菜单命令的ID。由于命令的标识包含GUID,所以在这个文件中能找到一些guid 开头的"宏",Command标识中的无符号整数部分,则以IDM_VS、IDG_VS或一些其他的前缀开头。

msobtnid.h

这个文件表示在Microsoft Office 中用到的命令的ID。

 

     这些头文件可以在VS 2008 SDK安装目录的VisualStudioIntegration\Common\Inc子目录中找到。

     我们的package定义了自己的GUID和命令的ID,并且可能在.vsct 文件中多次使用到这些值。为了使vsct文件定义更简单并减少打字错误,我们可以在command table中增加Symbols节点,为这些GUID和命令ID设定标识符:

   1: <Symbols> 

   2:       <GuidSymbol name="guidStartupToolsetPkg" 

   3:             value="{1376bfe2-5278-493d-867e-2b5ba828368d}"/> 

   4:       <GuidSymbol name="guidStartupToolsetCmdSet" 

   5:             value="{ec3d3ea6-2261-4a18-a458-78591688e06d}"> 

   6:             <IDSymbol name="cmdidCalculateTool" value="0x0101"/> 

   7:       </GuidSymbol> 

   8:       <GuidSymbol name="guidImage" value="{91CB158E-29BC-4818-8C1F-967AF94D96B1}"> 

   9:             <IDSymbol name="bmpPic1" value="1"/> 

  10:       </GuidSymbol> 

  11: </Symbols>

     这样我们就可以用这些符号名而不是直接使用ID的值了,例如:

   1: <Bitmap guid="guidImage" href="Resources\Clock.bmp" usedList="bmpPic1"/>

     如你所见,GuidSymbol元素(用于定义逻辑容器的ID)可以包含IDSymbol元素(用于定义在容器内部的元素的ID)。

     现在,我们可以利用这些ID来定义界面的相关对象了。

     vsct文件用于定义命令,这些命令全部定义在Commands节点内。通过前面的文章我们可以知道,这些命令属于同一个package。Commands节点的package属性指定了这个package的ID:

   1: <Commands package="guidStartupToolsetPkg">

   2:   ...

   3: </Commands>

     为了定义一个命令,Commands节点下可以包含子节点,比如Groups、Buttons、Bitmaps等等。例如,如果我们要定义一个和命令相关的菜单项,我们可以把该菜单组定义在Groups下面的Group节点上,把菜单项定义在Buttons下面的Button节点上,把和该菜单相关的图片定义在Bitmaps节点内。

     在我们的vsct文件内,我们通过下面的代码段来定义我们的菜单项:

   1: <Buttons>

   2:   <Button guid="guidStartupToolsetCmdSet" id="cmdidCalculateTool"

   3:     priority="0x0100" type="Button">

   4:     <Parent guid="guidSHLMainMenu" id="IDG_VS_WNDO_OTRWNDWS1"/>

   5:     <Icon guid="guidIm

抱歉!评论已关闭.