zoukankan      html  css  js  c++  java
  • 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的职责

    1. 负责配置的加载
    2. 向VS注册控件
    3. 响应用户的点击及其他事件

    三、概要设计

    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接口。

     View Code

    CommandMenu继承CommandControl,特有子菜单相关属性。

    其中SubMenus属性可在编程时操纵,SubGeneratorType为配置文件中定义的供反射用的子菜单生成器类型,用于启动时根据特定数据源自动生成。

     View Code

    2、类图

     调用关系 :

    • Connect对象启动时加载CommandConfig,生成一个Plugin对象传给CommandManager,并向Host.Instance注册;CommandManager加载CommandConfig描述的所有控件
    • Connect.OnConnection方法调用CommandManager.Load方法
    • Connect.Exec方法调用CommandManager.Execute方法
    • Connect.OnDisconnection方法调用CommandManager.Disconnect方法

    四、源代码

    http://vssharp.codeplex.com/

    ---------------------------------------------------

    下篇将以一个实例来讲解框架的使用,敬请期待。

    作者:CnSharp.com
    本文版权归CnSharp.com和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
     
    分类: Open Source
  • 相关阅读:
    Linux进阶之Linux中的标准输入输出
    PermCheck
    FrogRiverOne
    PermMissingElem
    FrogJmp
    TapeEquilibrium
    恒生电子长沙2016实习生笔试题
    接口和抽象类的异同点?
    C#实现二叉树
    C#实现栈和队列
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4584845.html
Copyright © 2011-2022 走看看