要介绍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. Oracle编程入门经典 第12章 事务处理和并发控制

    目录 12.1          什么是事务处理... 1 12.2          事务处理控制语句... 1 12.2.1       COMMIT处理... 2 12.2.2       RO ...

  2. April 21 2017 Week 16 Friday

    Courage is like a muscle. We strengthen it with use. 勇气就像肌肉,越使用越强大. Most often it is true, but somet ...

  3. 【转】如何手动添加Android Dependencies包

    在ADT16 之前可以在工程里面做关联,eclipse会在工程上自动添加ReferenceLibrary.新版本的ADT修改了第三方jar的导入方式,只需要在工程目录下新建libs文件夹,注意是lib ...

  4. P1980 计数问题

    题目描述 试计算在区间 11 到 nn的所有整数中,数字x(0 ≤ x ≤ 9)x(0≤x≤9)共出现了多少次?例如,在 11到1111中,即在 1,2,3,4,5,6,7,8,9,10,111,2, ...

  5. redis string类型

  6. 大数据(1)初始hadoop

    1.hadoop模型如下: (上图为Hadoop1.x的布局) (Hadoop2.x较Hadoop1.x,多了YARN) Hadoop框架,是一个庞大的生态系统. 或者我们可以这样理解: 可以把整个体 ...

  7. caffe新版本的各种软件

    系统重装了,于是,我想装就体验一下最新的各种东西吧. anaconda最新的 cuda最新的 cudnn最新的 本来安装好了没问题.caffe编译也通过了.但是不能用,缺少python opencv和 ...

  8. malloc动态分配字符串数组“ 一个月内的提醒”

    //输出一个月提醒 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_R ...

  9. MySQL存储引擎MyISAM与InnoDB

    一. MySQL存储引擎MyISAM与InnoDB如何选择 MySQL有多种存储引擎,每种存储引擎有各自的优缺点,可以择优选择使用:MyISAM.InnoDB.MERGE.MEMORY(HEAP).B ...

  10. udp发送广播消息

    import socket if __name__ == '__main__': # 创建udpsocket udp_socket = socket.socket(socket.AF_INET, so ...