上一次我们实现了一个带有命令(Command)的package,这一次让我们更进一步:创建一个被称为工具窗(Tool Window)的界面。那么,什么是工具窗呢?让我们想象一下:解决方案浏览器(Solution Explorer)、工具箱(Toolbox)、错误列表(Error List),它们都是工具窗(Tool Window)。

像前几篇一样,我们依然选择选择Visual Studio Integration Package类型作为项目类型,这一次我们把它命名为SimpleToolWindow。当项目向导出现后,我们选择C#做为开发语言,并利用向导为我们的程序集自动生成一个key文件。在VSPackage Information页面,我们输入如下内容:

在下一步,我们选中Tool Window复选框,以便为我们的package创建一个工具窗。

紧接着,向导会要求我们填入工具窗口的名字(标题)和对应命令的ID,请按照下图填入:

虽然我们没有选择菜单命令(Menu Command),但向导会帮我们在“视图|其他窗口”子菜单下帮我们创建一个菜单项。该菜单项会和我们的工具窗关联起来。

在向导的最后一步我们可以建立集成测试项目和单元测试项目,请勾掉这两个选项并且点击Finish按钮。向导会在几秒钟内帮我们创建项目的源文件。

生成并运行SimpleToolWindow项目。当Visual Studio实验室启动后,你可以在“视图|其他窗口”菜单下看到一个新的菜单项:

单击这个菜单项,就会打开我们的工具窗。通过拖动它的标题栏,可以移动它到任何位置或者固定它,就像其他的工具窗一样:

同时,向导帮这个工具窗生成了代码逻辑:当点击这个窗口的按钮时,它会弹出一个消息框。

源文件分析(What is inside?)

向导帮我们生成了PkgCmdID.cs文件,这个文件的功能和上一篇SimpleCommand中的一样。在这里这个文件定义了“视图|其他窗口”菜单下的命令MyToolWindow的标识符。

向导也生成了用于定义菜单资源的SimpleToolWindow.vsct文件,这和上一篇的SimpleCommand一样。

和上一篇的SimpleCommand相比,真正不一样的地方是这里多了两个新文件。MyControl.cs文件定义了工具窗用到的用户控件MyControl类,MyToolWindow.cs文件定义了应用MyControl实例的工具窗类。当我们改变工具窗的大小时,会自动改变嵌入的MyControl的大小。

现在让我们看一下MyControl控件的实例是怎样嵌入在工具窗中的,下面是MyToolWindow.cs文件中的代码:

   1: using System;
   2: using System.Windows.Forms;
   3: using System.Runtime.InteropServices;
   4: using Microsoft.VisualStudio.Shell;  
   5: namespace MyCompany.SimpleToolWindow
   6: {
   7:   [Guid("4469031d-23e0-483c-8566-ce978f6c9a6f")]
   8:   public class MyToolWindow : ToolWindowPane
   9:   {
  10:     private MyControl control;  
  11:  
  12:     public MyToolWindow() : base(null)
  13:     {
  14:       this.Caption = Resources.ToolWindowTitle;
  15:       this.BitmapResourceID = 301;
  16:       this.BitmapIndex = 1;
  17:       control = new MyControl();
  18:     }
  19:   
  20:     override public IWin32Window Window
  21:     {
  22:       get { return (IWin32Window)control; }
  23:     }
  24:   }
  25: }

MyToolWindow类继承了ToolWindowPane,这个基类又继承了基类WindowPane。WindowPane实现了很多接口,包括IVsWindowPane。所有在Visual Studio里的窗口形式的用户界面,都必须实现IVsWindowPane接口。另外,大家都知道,所有的VS-Managed对象都是COM对象,所以我们的工具窗的类必须要有一个GUID。

MyToolWidow类很简单:它嵌入了一个MyControl控件的实例,并在默认构造函数中初始化它。IDE和界面之间的联系是通过重写Window属性实现的,Window属性是一个实现了IWin32Window接口的对象,它返回的就是MyControl的实例。构造函数负责设置窗口的基本信息(标题和图标)。

现在是时候去瞧一瞧工具窗里用到的用户控件的代码了:

   1: using System.Security.Permissions;
   2: using System.Windows.Forms;
   3:   
   4: namespace MyCompany.SimpleToolWindow
   5: {
   6:   public partial class MyControl : UserControl
   7:   {
   8:     public MyControl()
   9:     {
  10:       InitializeComponent();
  11:     }
  12:   
  13:     [UIPermission(SecurityAction.LinkDemand, 
  14:       Window = UIPermissionWindow.AllWindows)]
  15:     protected override bool ProcessDialogChar(char charCode)
  16:     {
  17:       if (charCode != ' ' && ProcessMnemonic(charCode))
  18:       {
  19:         return true;
  20:       }
  21:       return base.ProcessDialogChar(charCode);
  22:     }
  23:   
  24:     protected override bool CanEnableIme
  25:     {
  26:       get { return true; }
  27:     }
  28:   
  29:     private void button1_Click(object sender, System.EventArgs e)
  30:     {
  31:       MessageBox.Show(this,
  32:         string.Format(System.Globalization.CultureInfo.CurrentUICulture, 
  33:         "We are inside {0}.button1_Click()", this.ToString()),
  34:         "My First Tool Window");
  35:     }
  36:   }
  37: }

我们的用户控件实在是太简单了。它的主要功能就是显示一个消息框,这个功能是在button1_click事件处理方法里实现的。这个工具窗的按钮支持助记符号“C”,所以我们可以按快捷键Alt+C来代替点击“Click Me"按钮。这个功能是通过ProcessDialogChar方法实现的。另外,为了允许我们的package能够支持IME(例如支持日本汉字输入),我们必须确认CanEnableIme属性返回true。

这就是做一个简单的工具窗所需要做的所有事情,但是我们还有很多事情要了解。

如何显示工具窗?

我们还需要利用“视图|其他窗口”菜单来显示这个工具窗。这个功能是在SimpleToolWindowPackage类中实现的。

工具窗自己并不是一个独立的对象,它和我们的package是有联系的:package包含了什么时候和怎样去显示工具窗的逻辑,当然也包含了和工具窗的互动逻辑以及其他服务。

我们可以通过在package类中标记ProvideToolWindowAttribute来关联到工具窗类。同时我们必须将我们的工具窗的类型作为一个参数传进去。

   1: ...
   2: [ProvideToolWindow(typeof(MyToolWindow))] 
   3: ...
   4: public sealed class SimpleToolWindowPackage : Package
   5: {
   6:   ...
   7: }

一个package可以(并且通常可以)包含多于一个的工具窗口,所以可以在package类上标记多个ProvideToolWindow属性。regpkg.exe会用些Attribute来为package注册工具窗。

仅仅注册工具窗还不足以将它显示出来,我们还必须要写一些代码去显示它。另外,由于一个工具窗可以有一个以上的实例,所以我们必须管理他们。在我们的例子中,VSPackage向导创建了MyToolWindow的一个单一的实例(姑且称为它单例)以及下面的代码去显示它(在SimpleToolWindowPackage类里):

   1: private void ShowToolWindow(object sender, EventArgs e)
   2: {
   3:   ToolWindowPane window = this.FindToolWindow(typeof(MyToolWindow), 0, true);
   4:   if ((null == window) || (null == window.Frame))
   5:   {
   6:     throw new NotSupportedException(Resources.CanNotCreateWindow);
   7:   }
   8:   IVsWindowFrame windowFrame = (IVsWindowFrame)window.Frame;
   9:   Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(windowFrame.Show());
  10: }
  11:  

工具窗实例管理的关键在于FindToolWindow方法。它有3个参数。第一个参数是工具窗的类型,第二个参数定义了工具窗实例的ID。从这个方法的名字上看来,我们猜测它将返回相应工具窗的实例。但是如果我们根本没有创建它,我们又怎能返回一个工具窗的实例呢?答案是FindToolWindow的第三个参数:如果实例不存在的话,true将使这个方法创建该工具窗类的一个新实例(用指定的实例ID),并返回这个新创建的窗口实例。这就是这段代码实际上做的:它利用(创建或者查找)一个单一的MyToolWindow实例,该实例的ID是0。

工具窗(或任何Visual Studio里的其他窗口)显示在实现了IVsWindowFrame接口的框(Frame)里,这个框提供了诸如位置、显示、隐藏等功能。为了显示工具窗,我们必须得到这个框,并调用它的Show方法。

只有成功了实例化了窗口并有一个有效的框(Frame)时,窗口才能够显示。

我们离完成这个例子只有一步之遥了:只剩下把事件处理逻辑关联到菜单项了。它和我们上一个例子SimpleCommand采用相同的代码,这一点都不奇怪。下面是在Initialize方法中的代码,我们只是回顾一下:

   1: protected override void Initialize()
   2: {
   3:   Trace.WriteLine (string.Format(CultureInfo.CurrentCulture, 
   4:     "Entering Initialize() of: {0}", this.ToString()));
   5:     base.Initialize();
   6:   
   7:   OleMenuCommandService mcs = 
   8:     GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
   9:   if ( null != mcs )
  10:   {
  11:     CommandID toolwndCommandID = 
  12:       new CommandID(GuidList.guidSimpleToolWindowCmdSet,  
  13:       (int)PkgCmdIDList.cmdidMyFirstTool);
  14:     MenuCommand menuToolWin = new MenuCommand(ShowToolWindow, toolwndCommandID);
  15:     mcs.AddCommand( menuToolWin );
  16:   }
  17: }

如果你忘记了菜单命令和它们的事件处理逻辑是怎样关联的,请重新阅读SimpleCommand这一篇。

总结

在这个非常简单的package里,我们创建了一个工具窗,当点击工具窗里的按钮的时候,弹出一个消息框。我们用到了与SimpleCommand这个package里同样的方法去创建一个菜单命令,这个命令负责显示工具窗。另外,VSPackage向导增加了一些新的代码去实现期望的效果:

— 用户界面(包含“Click Me!”按钮的控件)是一个简单WinForm用户控件。

— 工具窗类继承自ToolWindowPane,嵌入并实例化我们的用户控件;并且重写Window属性以便把这个用户控件的实例提供出去。

— 创建了一段事件处理方法,并调用package的FindToolWindow方法。通过调用工具窗所在的Frame的Show方法来显示工具窗。

— 在package的初始化代码里,加入菜单命令和事件处理方法的关联代码。

原文链接:http://dotneteers.net/blogs/divedeeper/archive/2008/01/08/LearnVSXNowPart4.aspx

自定制vs插件--LearnVSXNow!-#4 创建一个带有工具窗的Package相关推荐

  1. 创建一个带有Lookup字段的List

    用程序去创建一个List是非常简单的事情,但是如何去创建一个带有Lookup类型的字段呢? 这就是本篇文章要尝试去做的事情. 前期准备工作: 在站点上有一个List,叫UserInformation, ...

  2. java 广告插件_徒手创建一个chrome扩展-屏蔽广告插件

    创建一个文件夹,创建以下文件 maniftest.json  background.js和 icon图片 maniftest.json文件设置如下 { "name": " ...

  3. 创建一个带有Event Receiver的List Definition

    文章中介绍了详细的步骤, 还有一个视频可供下载. 文章地址: Building List Definitions with Event Receiver in Windows SharePoint S ...

  4. SQL Server创建一个带有输入和输出参数的存储过程并调用

    --创建一个表Borrow的的存储过程,输入参数是Borrow表的B_ID,输出参数Books表的B_Name create proc P_Test1 @B_ID char(5), --输入参数 @B ...

  5. Carla学习(六) 创建一个带有各种传感器的车辆

    1 在catkin_ws工作空间中,创建一个程序包,这里命名sensor_vehicle.这里程序包不需要依赖,因为之后直接拷贝官网给的创建车辆的程序包. ~$ cd catkin_ws/src/ro ...

  6. java怎么添加到按钮组_如何在Java中创建一个带有连接按钮的ButtonGroup?

    我目前正在尝试创建一组切换按钮,这些按钮类似于Eclipse的格式化程序首选项中使用的按钮: 目前我已通过以下方式尝试此操作: public class Exercise extends JFrame ...

  7. java swing工具栏_javaSwing如何创建一个有工具条和菜单的窗口

    不多说,直接上代码了哈! 源代码: package edu.sdkd.ch02; import java.awt.BorderLayout; import java.awt.Dimension; im ...

  8. 【Interfacenavigation】用RecyclerView创建一个列表(4)

    原 如果您的应用程序需要基于大型数据集(或经常更改的数据)显示元素滚动列表,则应RecyclerView 按照本页所述使用. 提示:通过单击文件>新建>片段>片段(列表),从Andr ...

  9. 抱抱脸(hugging face)教程-中文翻译-创建一个自定义架构

    创建一个自定义架构 AutoClass 自动推导模型架构,并下载预先训练的配置和权重.通常,我们建议使用 AutoClass 生成与检查点无关的代码.但是,想要更多地控制特定模型参数的用户可以从几个基 ...

最新文章

  1. RISC-V架构上的Debian和Fedora现状
  2. BCH或将在年底超越ETH
  3. 《Android游戏开发详解》——第1章,第1.6节函数(在Java中称为“方法”更好)...
  4. 【MFC两种视频图像採集方法】DirectShow与Opencv
  5. 【Normal Form】数据库表结构设计所遵从的范式
  6. 钉钉开发者接口文档_无需开发,IT事件接入钉钉的方法详解
  7. 联通定时休眠5G基站 戳破皇帝的新衣
  8. icinga2 php模块,在Ubuntu 18.04系统上安装Icinga2监视工具的方法
  9. 713C - 如何进入一个研究领域
  10. php输出下载地址,PHP实现的文件直接输出下载
  11. Obective-C之宏定义
  12. 大学计算机基础学后感想,大学计算机基础学习感想
  13. halcon 将数据保存到excel_halcon保存数据到excel表格-怎样把图像里面的数据提取到excel表格里面去?...
  14. 客运综合管理系统项目—售票管理(售票)
  15. 软件测试基础知识:按照测试实施组织,可将测试划分为开发方测试、用户测试、第三方测试。下面关于开发方测试的描述正确的是______。
  16. 【Windows、Git问题】detected dubious ownership in repository 问题解决
  17. ThreadLocal源码解析2.ThreadLocalMap
  18. 图文并茂!推荐算法架构——粗排
  19. Python环境配置和安装包总结
  20. flowable 监听器

热门文章

  1. 从零开始,申请开通微信小程序全流程
  2. 【iOS】动态更换图标
  3. 3分钟快速搭建ngrok服务器
  4. [Swift]对UIView截图
  5. linux centos ubuntu 网络图标消失的解决办法
  6. 曹工2020年终总结--当我在说下一篇的时候,我在说什么(一个7年程序员的2020之旅,已上岸腾讯,欢迎找我内推)
  7. Java点名器,文章中内含源码
  8. 优思学院|取得六西格玛黑带经验谈
  9. DreamPlan Plus for Mac(家装和景观设计软件)
  10. 集线器(Hub)、网线、网卡、交换机、路由器分别工作在OSI参考模型的哪一层?