VS扩展开发框架
上篇:设计
一、引子
自2008年起开发SSMS插件SqlSharp(er)的过程中,有一天发现多数代码都大同小异,就像这样。

Commands2 commands = (Commands2)_applicationObject.Commands;
string toolsMenuName = "Tools"; //Place the command on the tools menu.
//Find the MenuBar command bar, which is the top-level command bar holding all the main menu items:
Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar = ((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars)["MenuBar"]; //Find the Tools command bar on the MenuBar command bar:
CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName];
CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl; //This try/catch block can be duplicated if you wish to add multiple commands to be handled by your Add-in,
// just make sure you also update the QueryStatus/Exec method to include the new command names.
try
{
//Add a command to the Commands collection:
// add + (int)vsCommandStatus.vsCommandStatusEnabled if we want the default state to be enabled
Command command = commands.AddNamedCommand2(_addInInstance, "FormatSQL", "Format SQL", "Format SQL", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton); //Add a control for the command to the tools menu:
if ((command != null) && (toolsPopup != null))
{
command.AddControl(toolsPopup.CommandBar, 1);
}
}
catch (System.ArgumentException)
{
//If we are here, then the exception is probably because a command with that name
// already exists. If so there is no need to recreate the command and we can
// safely ignore the exception.
}

于是萌生出开发一个框架的想法。
于是有了一个叫SsmsSharp的框架,后正式命名为SqlSharp发布到了CodePlex上。
与此同时,将操纵EnvDTE的代码与SSMS Objects的代码分离,操纵EnvDTE的代码就形成了本篇要说的VsSharp。
后来,当我正式使用VsSharp开发VS扩展时,又引出一些新问题如源代码签出、一个VS搭载多个扩展,解决这些问题后,VsSharp开始成熟起来。
二、设计思路
1、目标
应用Command模式,定义每个控件的行为。将一个个控件的属性与行为集合在一个配置文件中,在VS启动时自动加载控件,点击控件时通过反射触发相应的命令。
2、流程
User:终端用户(也就是各位码农)
Host:VS实例,提供全局的EnvDTE对象访问器,注册Plugin,响应IDE的各种事件(如文档打开关闭等)
Plugin:基于VsSharp开发的插件(此处为避免与EnvDTE.AddIn重名,命名为Plugin)
由此引出VsSharp的职责
- 负责配置的加载
- 向VS注册控件
- 响应用户的点击及其他事件
三、概要设计
1、对象设计
1.1 基于上述职责定义,抽象出如下对象:
- CommandConfig:负责命令与控件的配置描述
- CommandManager:负责配置的加载,和与VS的交互
- CommandBarAccessor:与VS直接交互的对象,实现ICommandBarAccessor接口,主要是为了隔离VS版本的差异
- Host:宿主,单例,表示当前操作的VS实例;CommandAccessor通过它与EnvDTE交互
- PlugIn:主要属性为CommandConfig和Connect入口的Assembly
CommandBarAccessor的行为:

public interface ICommandBarAccessor
{
void AddControl(CommandControl control);
void ResetControl(CommandControl control);
void EnableControls(IEnumerable<string> ids ,bool enabled);
void Delete();
}

- AddContro:添加一个控件
- ResetControl:重置控件,比如某控件的子菜单可以依赖于特定的配置或数据源,当配置或数据源发生变化时,需要重新加载控件
- EnableControl:启用(禁用)控件,比如某些控件是用于操作文档的,当有文档打开时才启用
- Delete:删除控件,当VS退出时执行Disconnect方法时触发
1.2 命令接口
public interface ICommand
{
void Execute(object arg = null);
}
命令类型:

public enum CommandActionType
{
Menu,
Program,
Window,
Dialog
}

- Menu:缺省类型,无任何行为
- Program:执行一段程序
- Window:打开一个窗体
- Dialog:打开一个模态窗体
1.3 命令控件描述
主要有两种控件类型:
- CommandMenu:包括主菜单栏的自定义菜单、上下文菜单,其下级可以有子菜单
- CommandButton:主要是插入ToolStrip的ToolStripButton,其下级也可以有子菜单
抽象类CommandControl:CommandMenu和CommandButton的父类,描述控件的ID、文本、图标、命令类型、位置、所属父控件等属性。
以下代码段为CommandControl的全部属性。
其中,
ClassName为供反射用的动作类型名称,当CommandActionType为Program时,要求该类型实现了ICommand接口。
CommandMenu继承CommandControl,特有子菜单相关属性。
其中SubMenus属性可在编程时操纵,SubGeneratorType为配置文件中定义的供反射用的子菜单生成器类型,用于启动时根据特定数据源自动生成。
2、类图
调用关系 :
- Connect对象启动时加载CommandConfig,生成一个Plugin对象传给CommandManager,并向Host.Instance注册;CommandManager加载CommandConfig描述的所有控件
- Connect.OnConnection方法调用CommandManager.Load方法
- Connect.Exec方法调用CommandManager.Execute方法
- Connect.OnDisconnection方法调用CommandManager.Disconnect方法
四、源代码
---------------------------------------------------
下篇将以一个实例来讲解框架的使用,敬请期待。
VS扩展开发框架的更多相关文章
- VsSharp:一个VS扩展开发框架(上)
上篇:设计 一.引子 自2008年起开发SSMS插件SqlSharp(er)的过程中,有一天发现多数代码都大同小异,就像这样. Commands2 commands = (Commands2)_app ...
- Linux 搭建php扩展开发框架
1.安装phpize(如果是使用php源码编译就免了,本身就有) 2.打开php源码,ext中有ext_skel工具,使用它可以方便 ./ext_skel --extname = myext 生成扩展 ...
- VS2012编译php扩展
注意:用VS2015来做会比较好! 开发前准备工作:cygwinvisual studio 2012php编译后的程序 使用的是 xampp集成安装包,所以编译后的程序路径为D:\xampp ...
- 几种流行Webservice框架性能对比(转载)
1摘要 开发webservice应用程序中离不开框架的支持,当open-open网站列举的就有很多种,这对于开发者如何选择带来一定的疑惑.性能Webservice的关键要素,不同的框架性能上存在较大差 ...
- DDD开发框架ABP之本地化资源的数据库存储扩展
在上一篇<DDD开发框架ABP之本地化/多语言支持>中,我们知道,ABP开发框架中本地化资源存储可以采用XML文件,RESX资源文件,也提供了其他自定义的存储方式的扩展接口.ABP框架默认 ...
- 在开发框架中扩展微软企业库,支持使用ODP.NET(Oracle.ManagedDataAccess.dll)访问Oracle数据库
在前面随笔<在代码生成工具Database2Sharp中使用ODP.NET(Oracle.ManagedDataAccess.dll)访问Oracle数据库,实现免安装Oracle客户端,兼容3 ...
- vue+.netcore可支持业务代码扩展的开发框架 VOL.Vue 2.0版本发布
框架介绍 这是一个基于vue.element-ui.iview..netcore3.1 可支持前端.后台动态扩展业务代码快速开发框架. 框架内置定制开发的代码生成器,生成的代码不需要复制也不需要更改, ...
- [原创][开源]SunnyUI.Net, C# .Net WinForm开源控件库、工具类库、扩展类库、多页面开发框架
SunnyUI.Net, 基于 C# .Net WinForm 开源控件库.工具类库.扩展类库.多页面开发框架 Blog: https://www.cnblogs.com/yhuse Gitee: h ...
- SpringCloud微服务实战——搭建企业级开发框架(四十一):扩展JustAuth+SpringSecurity+Vue实现多租户系统微信扫码、钉钉扫码等第三方登录
前面我们详细介绍了SSO.OAuth2的定义和实现原理,也举例说明了如何在微服务框架中使用spring-security-oauth2实现单点登录授权服务器和单点登录客户端.目前很多平台都提供了单 ...
随机推荐
- Light OJ Dynamic Programming
免费做一样新 1004 - Monkey Banana Problem 号码塔 1005 - Rooks 排列 1013 - Love Calculator LCS变形 dp[i][j][k]对于第一 ...
- SPOJ PT07X Vertex Cover
题目意思: 一棵树,找到最少的点能覆盖到所有的边,(也就是每条边俩端 至少有一个在你找到的集合): 解法:每条边只能被俩个点中的一个,或全部覆盖所以我们有树形DP来解: DP[num][flag]// ...
- effective c++ 条款9 do not call virtual function in constructor or deconstructor
在构造函数中不要调用virtual函数,调用了也不会有预期的效果. 举个例子 class Transaction { public: Transaction() { log(); } ; } clas ...
- git 常用命令及问题解决(转)
git init 产生的目录解释error: src refspec master does not match any.引起该错误的原因是,目录中没有文件,空目录是不能提交上去的error: ins ...
- Cocos2d-x3.1回调函数具体解释
Cocos2d-x3.1回调函数的定义CCRef.h声明.源代码,例如,下面的: typedef void (Ref::*SEL_CallFunc)(); typedef void (Ref::*SE ...
- SQL server 2005 PIVOT运算符的使用
原文:SQL server 2005 PIVOT运算符的使用 PIVOT,UNPIVOT运算符是SQL server 2005支持的新功能之一,主要用来实现行到列的转换.本文主要介绍PIVOT运算符的 ...
- HDU 3829 Cat VS Dog
题意: p个人 每一个人有喜欢和讨厌的动物 假设选出的动物中包括这个人喜欢的动物同一时候不包括他讨厌的动物那么这个人会开心 问 最多几个人开心 思路: 二分图最大独立集 利用人与人之间的冲突 ...
- cocos2d-html5
cocos2d-html5 简单的混乱 在正常情况下,build设置完毕后 跑ant编 变更后cocos2d.js 简单直观so easy 只需要上传cocos2d.js/game.js/index文 ...
- linux shell中间$0,$?,$!和<<'END'
变量说明: $$ Shell自己PID(ProcessID) $! Shell背景上次执行Process的PID $? 最后执行的命令结束码(回报值) $- 使用Set命令设定的Flag一览 $* 全 ...
- 软测试是一个烂摊子?NO——【软测试】
软测试是一个烂摊子权?我开始也是这么认为的.这充分证明,.我并没有考虑,整个合并没有类似的项目. 前几天跟慕夏交流了怎样做总结,听完她讲的,我開始学着为细节的知识点找联系. 只是今天跟老师一交流,才发 ...