面向.Net程序员的VS扩展

本文分2部分 第一为自定义多项目模板 第二为vs add-in开发

文章所有vs版本为2010



效果图

1.自定义模板

2. 工具菜单

3.窗口

4.工程

5.文件

...



一. 多项目模板

单项目模板做起来很简单 选中一个项目在文件一栏中选中导出模板

然后选择项目模板

在最后一项向导会给出你的输出路径,一般都是系统的用户文档路径+\Visual Studio 2010\My Exported Templates

在对应目录下会生成你对应的项目模板压缩包

我们生成2个项目的模板文件 然后做一个多项目模板

我们解压2个模板文件并且放进一个新建的名称为MaoyaTemplates的文件夹 剪切到Visual Studio 2010\Templates\ProjectTemplates路径下

新建模板文件MyTemplate.vstemplate

根据要定义的模板内容 修改文件

然后将整个文件夹压缩成zip文件即可 在TemplateData可以定义一些自己需要的信息 例如icon定义你的模板图标 把图标文件放在相对路径即可

然后重新打开vs 即可看到刚才作成的模板

打开以后就是定义的2个demo工程 相当简单

这样就不用每次来新项目都去copy代码了



二 vs插件

概念性的东西可以参考 http://msdn.microsoft.com/zh-cn/library/bb384200.aspx

直接上干货

vs插件可以帮助或者优化你在vs开发过程的大部分窗口 它可以针对文件 针对项目 针对窗口 甚至针对不同的后缀做不同的处理

下面图文+代码介绍开发步骤(vs2010)

选择插件项目 进入向导根据自己的场景选择即可

中间向导过程略过 最后一步

完成向导后 默认工程框架如下

最关键的就是connect.cs文件

Connect 继承了2个类 IDTExtensibility2, IDTCommandTarget

IDTExtensibility2 包含在实现接口时用作事件的方法。 每当发生影响某个外接程序的事件时(如加载或卸载该外接程序时)以及对该外接程序进行任何更改时,Visual Studio 都会调用这些方法。

IDTCommandTarget 接口使开发者得以在环境中实现命名命令。 并且以定义命令状态或执行命令。

每个方法的描述

中文版可以参考msdn

http://msdn.microsoft.com/zh-cn/library/extensibility.idtextensibility2.aspx

http://msdn.microsoft.com/zh-cn/library/envdte.idtcommandtarget.aspx

其中我们作为入门开发 需要关注得的是

OnConnection 为IDTExtensibility2的 main 方法,这是因为每次加载外接程序时都会调用该方法。 该方法为外接程序在加载时的入口点,因此可以将要在外接程序启动时运行的任何代码放置在此处(或调用任何其他函数)。

void OnConnection(
	Object Application,
	ext_ConnectMode ConnectMode,
	Object AddInInst,
	ref Array custom
)

参数
Application
类型:System.Object
对集成开发环境 (IDE) 的一个实例 (DTE) 的引用,该实例是 Visual Studio 自动化模型的根对象。
ConnectMode
类型:Extensibility.ext_ConnectMode
一个 ext_ConnectMode 枚举值,指示向 Visual Studio 中加载外接程序的方式。
AddInInst
类型:System.Object
一个对外接程序自己的实例的 AddIn 引用。 此引用存储起来以供以后使用(如用于确定外接程序的父集合)。
custom
类型:System.Array
一个空数组,可用来传递在外接程序中使用的特定于主机的数据。

下面我们开始建一个工具栏(Tools)下的菜单

首先判断加载方式

if (connectMode == ext_ConnectMode.ext_cm_UISetup || connectMode == ext_ConnectMode.ext_cm_Startup ||
                connectMode == ext_ConnectMode.ext_cm_AfterStartup)

  这里的ConnectMode来自一个枚举 参考msdn http://msdn.microsoft.com/zh-cn/library/extensibility.ext_connectmode.aspx

然后添加注册插件命令和窗口 关键代码:

                    var toolsBar = commandBars[Tools];

                    if (toolsBar != null)
                    {
                        toolsSubPopup = (CommandBarPopup)toolsBar.Controls.Add(MsoControlType.msoControlPopup, Type.Missing, Type.Missing, 1, true);
                        toolsSubPopup.Caption = MainMenuName;
                        CommandBar toolsSubBar = toolsSubPopup.CommandBar;

                        Command command = commands.AddNamedCommand2(
                            _addInInstance,
                            MenuName1,
                            MenuName1,
                            MenuName1,
                            true,
                            190,
                            ref contextGUIDS,
                            (int)vsCommandStatus.vsCommandStatusUnsupported + (int)vsCommandStatus.vsCommandStatusEnabled);
                        command.AddControl(toolsSubBar);

                        command = commands.AddNamedCommand2(
                            _addInInstance,
                            MenuName2,
                            MenuName2,
                            MenuName2,
                            true,
                            190,
                            ref contextGUIDS,
                            (int)vsCommandStatus.vsCommandStatusUnsupported + (int)vsCommandStatus.vsCommandStatusEnabled);
                        command.AddControl(toolsSubBar, 2);
                    }

  commandBars[Tools]表示命令栏中的工具栏,这里Tools实际为定义的字符串“Tools”。

  CommandBarPopup表示弹出命令条。

  _addInInstance表示当前插件实例。

  3个Menuname分别表示命令名称的缩写形式,UI显示的名称以及当用户将鼠标指针悬停在任何绑定到新命令的控件上时所显示的文本。

  true表示下面的190 为 Microsoft Office 位图的 ID。

  ContextUIGUIDs表示GUID 确定哪些环境上下文 (即调试模式,设计模式,等等) 显示命令。

  vsCommandStatusValue确定命令的禁用条件是不可见或禁用,当您提供一个 ContextUIGUIDs 参数,并且都不是当前活动的。

  AddNamedCommand2 创建命名命令,该命令由环境保存,并且在下次环境启动时(无论是否加载外接程序)可用。 外接程序以后可以通过响应 QueryStatus 方法来更改 ButtonText 名称。 如果文本以 # 开头,则该字符串的其余部分是一个整数,该整数表示外接程序已注册的附属 DLL 中的资源 ID。有两个默认值顺序状态:该默认值启用了状态和默认值可见性状态。 这些默认状态很重要,如果找不到命令处理程序 (因为该元素未加载或不实现 IDTCommandTarget)。 如果您的组件加载并实现 IDTCommandTarget,默认值不适用。

  Command.AddControl创建此命令的持久性命令栏控件。后面的数字表示菜单位置。

  详细参考http://msdn.microsoft.com/zh-cn/library/envdte80.commands2.addnamedcommand2.aspx

  这样基本上就完成了下图所示的效果

  但是我们需要对2个菜单进行功能型的开发

  QueryStatus方法返回指定的已命名命令的当前状态(启用、禁用、隐藏等)。

  在此方法添加片段

  if (neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
            {
                if (commandName == GetCommandName(MainMenuName))
                {
                    status = vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
                    return;
                }
        }

  vsCommandStatusSupported表示命令在此上下文中受支持,vsCommandStatusEnabled表示命令当前处于启用状态。

  Exec方法执行指定的命名命令。

            if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
            {
                if (commandName == GetCommandName(MainMenuName))
                {
                    MessageBox.Show("This is maoya test");
                    handled = true;
                    return;
                }

                if (commandName == GetCommandName(MenuName1))
                {
                    MessageBox.Show("This is maoya Test1 test");
                    handled = true;
                    return;
                }

                if (commandName == GetCommandName(MenuName2))
                {
                    MessageBox.Show("This is maoya Test2 test");
                    handled = true;
                    return;
                }

            }

  这里实现的很简单就是弹出个winform。你可以在这里实现很丰富的功能。



上面是工具栏的实现,下面介绍个操作窗口的

  Onconnection:

                    CommandBar mdiCommandBar = commandBars["Easy MDI Document Window"];
                    if (mdiCommandBar != null)
                    {
                        Command mdiCmd = commands.AddNamedCommand2(_addInInstance, MenuName3,
                                                                            MenuName3,
                                                                            MenuName3, false, 0,
                                                                            ref contextGUIDS);

                        mdiCmd.AddControl(mdiCommandBar);
                    }

  QueryStatus:

            if (commandName == GetCommandName(MenuName3) || commandName == GetCommandName(MenuName4) || commandName == GetCommandName(MenuName5))
            {
                status = vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
                return;
            }

  Exec 功能是新建一个文件

            if (commandName == GetCommandName(MenuName3))
            {
                _applicationObject.ExecuteCommand("File.NewFile", string.Empty);
                handled = true;
                return;
            }

  



  下面我们在做一个针对项目工程的自定义按钮

  OnConnection:

 CommandBar projectBar = commandBars["Project"];
                    if (projectBar != null)
                    {
                        projectSubPopup = (CommandBarPopup)projectBar.Controls.Add(MsoControlType.msoControlPopup, Type.Missing, Type.Missing, 1, true);
                        projectSubPopup.Caption = MainMenuName;
                        CommandBar projectSubBar = projectSubPopup.CommandBar;
                        Command projectCommand = commands.AddNamedCommand2(
                                                   _addInInstance,
                                                   MenuName4,
                                                   MenuName4,
                                                   MenuName4,
                                                   true,
                                                   190,
                                                   ref contextGUIDS,
                                                   (int)vsCommandStatus.vsCommandStatusUnsupported + (int)vsCommandStatus.vsCommandStatusEnabled);

                        if (projectSubBar != null)
                        {
                            projectCommand.AddControl(projectSubBar, 1);
                        }

                    }

  QueryStatus:

            if (commandName == GetCommandName(MenuName3) || commandName == GetCommandName(MenuName4) || commandName == GetCommandName(MenuName5))
            {
                status = vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
                return;
            }

  Exec 这里可以抓到你选择的是哪一个项目 包括名称 路径等等 根据具体的需求再来处理对应的逻辑

  if (commandName == GetCommandName(MenuName4))
            {
                MessageBox.Show(string.Format("This is maoya {0} test,/r/n该项目名称为{1}", MenuName4, _applicationObject.SelectedItems.Item(1).Name));
                handled = true;
                return;
            }

  

  

类似的还有操作文件,代码就不贴了 直接上图

值得一提你可以利用文件后缀等做一些特殊操作

在QueryStatus方法中添加

            if (commandName == GetCommandName(MenuName6))
            {
                var uiHierarchy = (UIHierarchy)_applicationObject.Windows.Item(
                        Constants.vsWindowKindSolutionExplorer).Object;
                if ((from UIHierarchyItem item in (Array)uiHierarchy.SelectedItems select item.Name).Any(itemName => itemName.IndexOf(".config") > -1))
                {
                    status = vsCommandStatus.vsCommandStatusEnabled | vsCommandStatus.vsCommandStatusSupported;
                }
            }

  



总结下来 vs的模板、插件扩展等可以给开发者带来极大的使用便利,例如你可以做代码生成器 或者针对dll文件直接调用一些反编译软件 而不用切出去再重开窗口找文件 等等 功能可大可小

希望对大家有帮助

时间: 2024-08-09 20:18:57

面向.Net程序员的VS扩展的相关文章

面向.Net程序员的dump分析

背景 Dump文件是进程的内存镜像.可以把程序的执行状态通过调试器保存到dump文件中.在 Windows 系统上, dump 文件分为内核 dump 和用户态 dump 两种.前者一般用来分析内核相关的问题,比如驱动程序:后者一般用来分析用户态程序的问题. 一般的程序员可能接触不到dump文件,反而是运维会用的多一些.不过如果你抗战在第一线,学会dump的分析无疑是掌握一柄利器.因为很多场景下,在线下的单元测试或者性能测试中由于测试用例的不充分或者生产与测试环境的硬件以及pv量级的不同等等情况

面向.Net程序员的前端优化

背景 作为web开发人员大家大多了解一些网站的性能优化方法,其实大部分方法都不复杂,例如针对前端js和css的压缩来减少请求大小,通过合并来减少请求次数.这里站在.Net后端程序员的角度来看一下如何最简单快捷的处理这一类需求. 全文分3节 combres,mvc4的Bundle,以及2者的对比和个人的意见观点. 弄了个很张扬的点赞样式,如果觉得很想吐槽请告诉我,我删掉... Combres Combres是一个.NET程序库,能够缩小,压缩,合并,以及缓存的JavaScript和CSS资源,AS

面向.Net程序员的后端性能优化实战

最近2个月没做什么新项目 完全是对于旧的系统进行性能优化 避免超时 死锁 数据处理能力不够等常见的性能问题 这里不从架构方面出发 毕竟动大手脚成本比较高 那么我们以实例为前提 从细节开始 优化角度 一.业务逻辑优化 二.DB优化 三.数据处理优化 四.锁与性能 五.cpu飙高小结 六.crash现象分析 业务逻辑优化 这一条不具有普遍性 不同的业务不同的场景 如果归纳起来 就是在不影响业务的前提下进行流程精简 1. 废弃冗余逻辑 常见于各种基于数据库的检查 很多同学在维护别人代码的时候 没有深入

面向.Net程序员的Sql版本管理

代码版本管理基本上程序员们都知道 TFS GIT SVN等等 但是对于数据库版本管理 java程序员或许会了解一些 但是.Net程序员收获的资料应该不多. 特别是现在云概念使用越来越广的情况下,与应用程序开发和部署常规管理数据库更改在一起便成为一个难题. 这里就分享一个用来进行sql版本管理的.net程序. 如图所示 因为只是研究着玩 暂时工具做的不复杂 提供版本跟进 回滚等基本功能 FluentMigrator : https://github.com/schambers/fluentmigr

很认真的聊一聊程序员的自我修养

首先要谈的是,今天的话题所聊的程序员包含哪些人? 在中国,写程序,不仅仅是一种兴趣,更多的时候,还是一种普通职业和谋生工具 大公司有厉害的程序员,优秀的架构师,但大量的小公司也有很多普通的程序员.在我这些年的工作经历中,也越来越深刻的感受到普通程序员的影响和力量.对于高阶程序员,所谓八仙过海各有神通,各有各的成就,各有各的修养,但程序员在达成较高的水平之前,有一些"自我修养",是最基础的,是普世的. 所以今天的话题面向的程序员,就是所有的正在写代码或者曾经写过代码的程序员,也包括广义上

C++_程序员_Protocol_Buffers_基础指南

摘要: 这篇教程提供了一个面向 C++ 程序员关于 protocol buffers 的基础介绍.通过创建一个简单的示例应用程序,它将向我们展示: 在 .proto 文件中定义消息格式 使用 protocol buffer 编译器 使用 C++ protocol buffer API 读写消息 这不是一个关于在 C++ 中使用 protocol buffers 的全面指南. 这篇教程提供了一个面向 C++ 程序员关于 protocol buffers 的基础介绍.通过创建一个简单的示例应用程序,

聊一聊程序员的自我修养

首先要谈的是,今天的话题所聊的程序员包含哪些人? 在中国,写程序,不仅仅是一种兴趣,更多的时候,还是一种普通职业和谋生工具 大公司有厉害的程序员,优秀的架构师,但大量的小公司也有很多普通的程序员.在我这些年的工作经历中,也越来越深刻的感受到普通程序员的影响和力量.对于高阶程序员,所谓八仙过海各有神通,各有各的成就,各有各的修养,但程序员在达成较高的水平之前,有一些"自我修养",是最基础的,是普世的. 所以今天的话题面向的程序员,就是所有的正在写代码或者曾经写过代码的程序员,也包括广义上

3年工作经验程序员应有的技能

每个程序员.或者说每个工作者都应该有自己的职业规划,如果看到这里的朋友没有自己的职业规划,希望你可以思考一下自己的将来... 因为和同事有约定再加上LZ自己也喜欢做完一件事之后进行总结,因此有了这篇文章.这篇文章大部分内容都是面向整个程序员群体的,当然因为LZ本身是做Java开发的,因此有一部分内容也是专门面向咱们Java程序员的. 简单先说一下,LZ坐标杭州,13届本科毕业,算上年前在阿里巴巴B2B事业部的面试,成都web前端培训一共有面试了有6家公司(因为LZ不想请假,因此只是每个晚上去其他

工作了3年的JAVA程序员应该具备什么技能?(zhuan)

http://www.500d.me/article/5441.html **************************************** 来源:五百丁 作者:LZ2016-03-18 因为和同事有约定再加上LZ自己也喜欢做完一件事之后进行总结,因此有了这篇文章.这篇文章大部分内容都是面向整个程序员群体的,当然因为LZ本身是做Java开发的,因此有一部分内容也是专门面向咱们Java程序员的. 简单先说一下,LZ坐标杭州,13届本科毕业,算上年前在阿里巴巴B2B事业部的面试,一共有