要介绍VSXTra项目不是一个简单的事情。 而且要在上面进行扩展,删减就更不容易。 源码分析的资料几乎没有,可怜的几个示例项目,相较而言,英文已经不是阻碍我前进的步伐了。 本篇只是简单的分析,对于已经使用到的几个接口或类型进行说明,不可能完整的,从全局去介绍VSXTra项目,建议读者还是去啃LearnVSXNow!系列,其中有不少的篇幅在介绍这个项目。

PackageBase


不管是CommandHandlerBase还是PowerCommands,都是简单的封装而已,但是VSXTra里的PackageBase并没有继承于Package,实际上它只是实现了几个接口。

这里首先要说的是IVsPackage这个接口。 VS2010使用MEF做扩展,实现了IVsPackage接口的会首先调用其SetSite方法,其实从PackageBase的InternalInitialize方法就可以看出两个调用的地方,另一个是IVsShellPropertyEvents的OnShellPropertyChange方法。 而并不是VS已启动就会加载VSPackage的,而是当你第一次使用该VSPackage的功能时才会加载,要实现自动加载VSPackage,你需要在你的VSPackage上标注自动运行才行,[ProvideAutoLoad(UIContextGuids.SolutionExists)]大概的意思就是,当解决方案存在的时候,该VSPackage自动加载。 这里没有使用VSXTra里所说的Typed GUID,而是直接使用UIContextGuids的常量定义,其实我现在仍然不知道这样写有什么好处。 之后在用户启动VS,打开某个解决方案时,IVsPackage的SetSite方法才会触发。 而IVsShellPropertyEvents的OnShellPropertyChange方法与IVsPackage的SetSite方法有所区别,SetSite对于每个VSPackage只会加载一次,而OnShellPropertyChange是当用户切换VSPackage时会触发,且里面那句经典的判断,能隔绝大多数情况的触发:

if ((int)__VSSPROPID.VSSPROPID_Zombie == propid)
{
if ((bool)propValue == false)
{
}
}

我已经不记得我如何得出以上结论,当然你肯定能想到,那都是很艰难很艰难的。

Command


我实在不想过多介绍PackageBase,这里借道Command缓冲缓冲。 当初如何实现一个Command以及PowerCommands对命令的简单封装我这里就不再啰嗦了,看看VSXTra里对Command的处理。

[CommandExecMethod]
[CommandId(GuidList.guidVSXtraMenuCommandCmdSetString,
CmdIDs.cmdidVSXtraMenuCommand)]
private void MyMenuCommand()
{
VsMessageBox.Show("Inside VSXtra Menu Command");
}

这是VSXTra里一个经典的实现方式,对于界面关系极少的VSPackage很有用,不需要其他任何代码,只在Package里加一个方法,标注几个Attribute即可,不可谓不方便。 可惜我的项目中,多个VSPackage共同组合,Command每个VSPackage中一大堆,即使使用分部类也过于麻烦。

[Guid(GuidList.guidCompileCmdSetString)]
public partial class BuildTradeGroup : CommandGroup<CompilePackage>
{
[CommandId(PkgCmdIDList.cmdidBuildTrade)]
public sealed class BuildTradeCommand : MenuCommandHandler
{
protected override void OnExecute(OleMenuCommand command)
{
}
}
}

VSXTra的示例项目中有这么一个例子,介绍了这种PowerCommands的分离方式。 可以看出,不同之处就是原本的CommandId是两个参数,需要传CmdSet的Guid,还要传Cmd的Id,而这里使用了CommandGroup去将其分类,这样以来确实看起来逻辑清楚,怎奈我还是想要每个命令一个文件的形式去做,所以这里使用了分部类,但是Guid只能在一个上面标注让我很是不爽,且每次新建命令,都忘了修改CommandId让人很是抓狂。 我在UnitTest专门对此进行检测。

再回首PackageBase


其实在VSXTra中,实现Command和PowerCommands中没有多大区别,关键代码就在PackageBase中。 在上面介绍的SetSite和OnShellPropertyChange方法中触发了InternalInitialize方法,其中又触发了BindCommandHandlers方法,而从传过来的程序集中就能看出其实现原理。 其实平淡无奇,只是遍历程序集中所有类,然后找出需要的类,通过Activator.CreateInstance方法实例化,进行相应的操作。 所以这里我扩展了对SolutionListeners和Configuration的初始化。 当然,PackageBase不只是对Command做了简化,比如说IVsPersistSolutionOpts接口就是对OptionPage进行的操作,而IVsToolWindowFactory接口就是对ToolWindow进行的操作。

Package中比较重要的一个方法GetService,其实是对IServiceProvider的GetService实现,期间嵌套了对IOleServiceProvider(Microsoft.VisualStudio.OLE.Interop.IServiceProvider)的QueryService实现。 读GetService很具挑战力,太过费心费力,这里不想继续了。

IServiceProvider接口是VSX开发中一个比较重要的接口,所以在PackageBase中对其做了全局实例,包括弹出框、DTE对象等一系列都需要使用IServiceProvider去获取。

PackageBase作为对Package的替代者,很多人只意识到继承关系,而其他诸如静态方法的实现却仍然使用Package提供的。 几乎所有Package实现的东西,PackageBase都能实现,且实现的更为方便快捷。 有一个简单而明显的例子,就是GetGlobalService方法,PackageBase对其做了三个重载,这也是在VSXTra项目中大量出现的一种重载方式,规范了很多调用方法。当然,不排除对于新接触的人各种疑惑。


前面简单的介绍了VSXTra开源框架,至于深究,还是算了,我只是祈祷我做的修改和扩展不会出错就好,而ProjectSystem项目更让我畏惧三分。 使用VSXTra确实能简化开发,而且更重要的是,在参考资料如此少的情况下,这么一个框架给我提供的就不只是简化开发而已,更多的是对VSX开发的进一步认识。

后续文章中可能会继续介绍VSXTra框架,分析其中一些具体的实现方式,以及我对VSXTra框架做的一些扩展。

VSX-4 VSXTra的更多相关文章

  1. 【Visual Studio】在VS2012中使用VSXtra

    最近工作中需要把之前为VS 2010写的扩展迁移到VS 2012上.在将工程版本改为VS2012之后,代码没有修改,直接编译通过,也可以安装到VS2012上. 不过,在实际使用的时候,却报错,提示“T ...

  2. VSX规划Package文件

    VSX是VS扩展,可以针对不同项目编写插件,虽然接触VSX的时间并不多,但是当了解VSX后深刻感受到VSX的魅力. VSX的材料比较少,配置文件也很繁琐,当初我也走了不少弯路. 这篇文章将帮助您更好的 ...

  3. VSX(翻译)Moving Code Blocks Among Code Regions using VS 2010 Extensions

    Moving Code Blocks Among Code Regions using VS 2010 Extensions (翻译)使用VS 2010 扩展性将代码块移至Region区域中 Down ...

  4. 【JZOJ2156】【2017.7.10普及】复仇者vsX战警之训练

    题目 月球上反凤凰装甲在凤凰之力附身霍普之前,将凤凰之力打成五份,分别附身在X战警五大战力上面辐射眼.白皇后.钢力士.秘客和纳摩上(好尴尬,汗). 在凤凰五使徒的至高的力量的威胁下,复仇者被迫逃到昆仑 ...

  5. C# base 64图片编码解码

    使用WinForm实现了图片base64编码解码的 效果图: 示例base 64编码字符串: /9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKD ...

  6. java web学习总结(二十七) -------------------JSP标签介绍

    一.JSP标签介绍 JSP标签也称之为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护. 二.JSP常用标签 ...

  7. Oracle学习笔记十 使用PL/SQL

    PL/SQL 简介 PL/SQL 是过程语言(Procedural Language)与结构化查询语言(SQL)结合而成的编程语言,是对 SQL 的扩展,它支持多种数据类型,如大对象和集合类型,可使用 ...

  8. PHP代码 如何网页获取用户的openid

    public function getOpenid($appid, $appsecret) { $SERVER_NAME = $_SERVER['SERVER_NAME']; $REQUEST_URI ...

  9. PHP中的header()函数作用

    PHP 中 header()函数的作用是给客户端发送头信息. 什么是头信息?这里只作简单解释,详细的自己看http协议.在 HTTP协议中,服务器端的回答(response)内容包括两部分:头信息(h ...

随机推荐

  1. Html + JS : 点击对应的按钮,进行选择是隐藏还是显示(用户回复功能)

    例如: 当我点击按钮1时,点击第一下进行显示This is comment 01,点击第二下隐藏This is comment 01 当我点击按钮2时,点击第一下进行显示This is comment ...

  2. IOS GCD (事例下载图片)

    @interface HMViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end @im ...

  3. redis 过期回调通知

    redis 过期回调通知 背景 在使用redis的过程中,有时我们会遇到这种情景,当key过期的时候,我们需要去重新做一些操作,比如重新生成value等.之前,一直用的是添加一个celery定时任务, ...

  4. JT796、JT808、JT809、JT1076、JT1077、JT1078部标平台过检道路运输车辆卫星定位系统企业视频监控平台检测登记表

    道路运输车辆卫星定位系统企业视频监控平台检测登记表的具体格式如下: 报名检测需要以下材料: 0检测报名须知.doc   点击下载 1检测意向单.doc   点击下载 2-1道路运输车辆卫星定位系统企业 ...

  5. Win10下安装zookeeper

    Win10下安装zookeeper 注册中心zookeeper的安装 0.去Apache官网下载zookeeper http://zookeeper.apache.org/ 2.找到解压路径的conf ...

  6. 微信 php 获取token 第二次失败解决办法

    第一次成功了,第二次总是失败,很简单,session问题 clearstatcache(); $_SESSION = ''; $_COOKIE = ''; //获得参数 signature nonce ...

  7. Servlet学习笔记01——什么是servlet?

    1.什么是Servlet? sun公司制订的一种用来扩展web服务器功能的组件规范. (1)扩展web服务器功能 早期的web服务器(apache web server,iis) 只能处理静态资源的请 ...

  8. Android和IOS网页不一致汇总

    1.input type=text 内容输入框的不一致,ios会默认给输入框添加自己的样式,导致在横向的输入框长度精准控制的时候,ios的输入框一般都比android上要长一点,还有内部阴影 解决此问 ...

  9. (转)IDE 而言,是 Xcode 的技术比较先进还是 Visual Studio?

    李如一他们弄得那个IT公论,最近有一期是吐槽ObjC的.吐到最后, @涛 吴 说,理想的用户界面语言应该是界面的描述和逻辑分开的,想了半天举不出例子来,其实说的不就是WPF吗?还在用Interface ...

  10. 用 js 写一个获取随机颜色的程序

    function getColor(){ var color="#"; for(var i=0;i<6;i++){ color+=(Math.random()*16 | 0) ...