VSX-4 VSXTra
要介绍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的更多相关文章
- 【Visual Studio】在VS2012中使用VSXtra
最近工作中需要把之前为VS 2010写的扩展迁移到VS 2012上.在将工程版本改为VS2012之后,代码没有修改,直接编译通过,也可以安装到VS2012上. 不过,在实际使用的时候,却报错,提示“T ...
- VSX规划Package文件
VSX是VS扩展,可以针对不同项目编写插件,虽然接触VSX的时间并不多,但是当了解VSX后深刻感受到VSX的魅力. VSX的材料比较少,配置文件也很繁琐,当初我也走了不少弯路. 这篇文章将帮助您更好的 ...
- 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 ...
- 【JZOJ2156】【2017.7.10普及】复仇者vsX战警之训练
题目 月球上反凤凰装甲在凤凰之力附身霍普之前,将凤凰之力打成五份,分别附身在X战警五大战力上面辐射眼.白皇后.钢力士.秘客和纳摩上(好尴尬,汗). 在凤凰五使徒的至高的力量的威胁下,复仇者被迫逃到昆仑 ...
- C# base 64图片编码解码
使用WinForm实现了图片base64编码解码的 效果图: 示例base 64编码字符串: /9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKD ...
- java web学习总结(二十七) -------------------JSP标签介绍
一.JSP标签介绍 JSP标签也称之为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护. 二.JSP常用标签 ...
- Oracle学习笔记十 使用PL/SQL
PL/SQL 简介 PL/SQL 是过程语言(Procedural Language)与结构化查询语言(SQL)结合而成的编程语言,是对 SQL 的扩展,它支持多种数据类型,如大对象和集合类型,可使用 ...
- PHP代码 如何网页获取用户的openid
public function getOpenid($appid, $appsecret) { $SERVER_NAME = $_SERVER['SERVER_NAME']; $REQUEST_URI ...
- PHP中的header()函数作用
PHP 中 header()函数的作用是给客户端发送头信息. 什么是头信息?这里只作简单解释,详细的自己看http协议.在 HTTP协议中,服务器端的回答(response)内容包括两部分:头信息(h ...
随机推荐
- Oracle编程入门经典 第12章 事务处理和并发控制
目录 12.1 什么是事务处理... 1 12.2 事务处理控制语句... 1 12.2.1 COMMIT处理... 2 12.2.2 RO ...
- April 21 2017 Week 16 Friday
Courage is like a muscle. We strengthen it with use. 勇气就像肌肉,越使用越强大. Most often it is true, but somet ...
- 【转】如何手动添加Android Dependencies包
在ADT16 之前可以在工程里面做关联,eclipse会在工程上自动添加ReferenceLibrary.新版本的ADT修改了第三方jar的导入方式,只需要在工程目录下新建libs文件夹,注意是lib ...
- 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, ...
- redis string类型
- 大数据(1)初始hadoop
1.hadoop模型如下: (上图为Hadoop1.x的布局) (Hadoop2.x较Hadoop1.x,多了YARN) Hadoop框架,是一个庞大的生态系统. 或者我们可以这样理解: 可以把整个体 ...
- caffe新版本的各种软件
系统重装了,于是,我想装就体验一下最新的各种东西吧. anaconda最新的 cuda最新的 cudnn最新的 本来安装好了没问题.caffe编译也通过了.但是不能用,缺少python opencv和 ...
- malloc动态分配字符串数组“ 一个月内的提醒”
//输出一个月提醒 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_R ...
- MySQL存储引擎MyISAM与InnoDB
一. MySQL存储引擎MyISAM与InnoDB如何选择 MySQL有多种存储引擎,每种存储引擎有各自的优缺点,可以择优选择使用:MyISAM.InnoDB.MERGE.MEMORY(HEAP).B ...
- udp发送广播消息
import socket if __name__ == '__main__': # 创建udpsocket udp_socket = socket.socket(socket.AF_INET, so ...