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 1406 Assassin`s Creed 减少国家DP+支撑点甚至通缩+最小路径覆盖
标题来源:problem=1406">Light OJ 1406 Assassin`s Creed 意甲冠军:向图 派出最少的人经过全部的城市 而且每一个人不能走别人走过的地方 思路: ...
- html风格的滚动条
DIV辊棒的设置 (CSS)2008/09/26 03:07div 控制滚动条2008年01月06日本 星期日 01:181)隐藏滚动条<body style="overflow-x: ...
- 【Web探索之旅】第三部分第一课:服务器
内容简介 1.第三部分第一课:服务器 2.第三部分第二课预告:IP地址和域名 第三部分第一课:服务器 大家好,欢迎来到[Web探索之旅]的第三部分.这一部分有不少原理,还是很重要的. 这一部分我们会着 ...
- 【C语言探索之旅】 第一部分第四课第一章:变量的世界之内存那档事
内容简介 1.课程大纲 2.第一部分第四课第一章:变量的世界之内存那档事 3.第一部分第四课第二章预告:变量的世界之声明变量 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答 ...
- VirtualBox创建虚拟电脑、执行Genymotion模拟器报错
当安装完Genynition关于Android应用的调试模拟器之后,在Genymotion执行的平台virtualBox:VirtualBox创建虚拟电脑.执行Genymotion模拟器报错: 错误卖 ...
- 1号店Interview小结
三大范式: 为了建立冗余较小.结构合理的数据库,设计数据库时必须遵循一定的规则.在关系型数据库中这种规则就称为范式.范式是符合某一种设计要求的总结.要想设计一个结构合理的关系型数据库,必须满足一定的范 ...
- Android应用程序绑定服务(bindService)的过程源码分析
Android应用程序组件Service与Activity一样,既能够在新的进程中启动,也能够在应用程序进程内部启动:前面我们已经分析了在新的进程中启动Service的过程,本文将要介绍在应用程序内部 ...
- Shell学问: 调用脚本之间
于Java,Python于,您可以使用import该方法使脚本或模块之间的呼叫,例如: >>> import math >>> math.sqrt(4) 2.0 在 ...
- Redis被攻击
记一次Redis被攻击的事件 最近几个月非常忙,所以很少有时间写博客,这几天终于闲了一些,于是就在整理平时的一些笔记.恰好这几天Redis服务器发生了问题,就记录一下. 我司有两款分别是2B和2C ...
- centos6.5 64位 openvpn安装配置(转)
查看系统版本cat /etc/redhat-releaseCentOS release 6.5 (Final) 查看内核和cpu架构uname -rm2.6.32-431.el6.x86_64 x86 ...