• VS2013在右键菜单添加命令插件开发


    一、选择Visual Studio Package模板建立插件项目

    由于此功能需要在右键菜单上添加命令,所以选择Visual Studio Package模板,根据模板向导步骤插件项目,在Select VSPackage Options步骤的时候选择Menu Command选项,如图-1所示:

    图-1

    接下来是设置命令的名称,如图-2所示

    图-2

    修改Command name的值,将其设置为我们要添加到右键菜单时的名称。Command ID可选择是否修改,值是一个十六进制数,由于标识我们的添加的命令。按照模板向导建立好插件项目后,按F5运行插件项目,此时VS会新建一个实验实例,点击工具菜单,可以看到已经有一个命令添加到工具菜单里了,如名称My Command name(如果没有修改Command name的值得话)如图-3所示:

    图-3

    点击该命令的时候会弹出一个提示框。现在有两个疑问:

    1、命令是如何与具体的功能关联?

    2、该命令是如何添加到工具菜单?

    对于第一个疑问:我们可以打开项目下以Package结尾的cs文件,该文件里有一个Initialize方法和一个MenuItemCallback事件处理方法,Package代码文件只有在我们点击命令的时候才会被

    加载运行。当我们点击命令的时候会依次调用构造函数、Initialize方法、MenuItemCallBack事件处理方法,MenuItemCallBack事件处理方法就是在Initialize方法里与我们的命令进行关联。

    对于第二个疑问:在项目的文件里我们可以找到一个以vsct(Visual Studio Command Table)为后缀的文件,命令就是通过该文件添加到工具菜单下的,项目在编译的时候会将该文件编译为二进制文件。

    二、vsct文件简介

    在vsct文件里,我们的菜单命令使用Button元素来表示的,如图-3所示:

    图-4

    Button元素的guid和id属性是该命令的唯一标识,这两个属性值分别在项目的Guids.cs和PkgCmdID.cs文件里定义了,priority表示命令在目标菜单的排列优先级。Parent子元素表示要将我们的命令添加到哪个菜单下面,如工具、帮助、右键菜单,id属性的值是Group元素的id属性值,如图-4所示。Icon元素是命令前的小图标,其属性值是在GuidSymbol元素定义的,如图-6所示。

    图-5

    Group元素定义了目标菜单的guid和id,也可以将图-4的guid和id换成guidSHLMainMenu和IDM_VS_MENU_TOOLS,这两种效果是一样的,都是将命令添加到右键菜单里。如果要按照图-4的方式设置guid和id值的话,需要事先知道目标菜单的guid和id值,并且要在Sysmbols元素里定义guid和id,如图-5所示:

    图-6

    除了红色框里的元素是我们自己定义的,其他的都是向导自动生成。那么为什么使用guidSHLMainMenu和IDM_VS_MENU_TOOLS作为guid和id两个属性的值的时候就不需要在Sysmbols元素里定义了呢?因为这两个元素的值已经在stdidcmd.h和vsshlids.h(C:Program Files (x86)Microsoft Visual Studio 12.0VSSDKVisualStudioIntegrationCommonInc)这两个文件里定义了,而这两个文件已经在vsct文件的开头就已经使用Extern元素引入了,所以就不需要我们再去定义了。

    三、如何获取目标菜单的guid和id值

    1、打开注册表编辑器(打开运行窗口,输入regedit),在[HKEY_CURRENT_USERSoftwareMicrosoftVisualStudio12.0General]找到该路径,右击-新建-DWORD(32-位)值(D),建立一个注册文件,将其命名为EnableVSIPLogging,并将其值改为1。按下Ctrl+Shift,用鼠标点击VS里的菜单,就会弹出一个VSDebug Message窗口,如图-6所示:

    图-7

    其中Guid和CmdID值就是我们需要的,NameLoc表示我们点击的菜单名称。

    四、设置命令只在xml文件的右键菜单里显示

    由于命令关联的操作都是在点击命令的时候才调用的,所以要实现此功能需要四个步骤才能实现:

    1、在Button元素加入子元素<CommandFlag>DynamicVisibility</CommandFlag>

    2、为Package类加入特性ProvideAutoLoad,该特性表示当满足条件的时候,事先加载该类里的相关运行。而条件是由该特性的构造函数来设置的,相关的条件已经定义为UIContextGuids80抽象类的常量字段了。

    3、将Initialize方法里的MenuCommand类改为OleMenuCommand类,并订阅OleMenuCommand类实例的BeforeQueryStatus事件,如图-8所示:

    图-8

    4、在BeforeQueryStatus事件处理函数里显示控制操作,如控制命令只在xml文件的右键菜单里才能显示,代码如下所示:

     1 private void menuItem_BeforeQueryStatus(object sender, EventArgs e)
     2 {
     3     OleMenuCommand menuCommand = sender as OleMenuCommand;
     4     if (menuCommand != null)
     5     {
     6     IntPtr hierarchyPtr, selectionContainerPtr;
     7        uint projectItemId;
     8        IVsMultiItemSelect mis;
     9        IVsMonitorSelection monitorSelection = (IVsMonitorSelection)Package.GetGlobalService(typeof(SVsShellMonitorSelection));
    10        monitorSelection.GetCurrentSelection(out hierarchyPtr, out projectItemId, out mis, out selectionContainerPtr);
    11 
    12        IVsHierarchy hierarchy = Marshal.GetTypedObjectForIUnknown(hierarchyPtr, typeof(IVsHierarchy)) as IVsHierarchy;
    13        if (hierarchy != null)
    14     {
    15       object value;
    16           hierarchy.GetProperty(projectItemId, (int)__VSHPROPID.VSHPROPID_Name, out value);
    17 
    18           if (value != null && value.ToString().EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
    19           {
    20             menuCommand.Visible = true;
    21           }
    22           else
    23           {
    24             menuCommand.Visible = false;
    25           }
    26     }
    27  }
    28 }

     到此,在xml文件的右键菜单里添加命令的功能已经实现。如图-9所示:

    图-9

    五、为命令添加关联功能

    添加功能可以在MenuItemCallBack事件处理函数里进行操作,需要判断当前的xml文件是否是新建的,如果是需要加上根元素,为了防止用户是在根元素所在行的后面点击命令(这样就找不到根元素),所以在开始查找操作之前需要将光标移到第一行,然后根据查找的结果判断是否需要添加根元素。如果是新建的xml文件的话可以直接将xml元素信息添加到第一行后面,如果已经存在根元素,则将根元素的结束元素替换成xml元素信息,代码如下所示:

    DTE dte = ServiceProvider.GlobalProvider.GetService(typeof(DTE)) as DTE;
    if (dte == null)
      return;
    TextSelection ts = dte.ActiveDocument.Selection as TextSelection;
    //防止用户在</mappings>结束符后进行操作,在结束符后操作的的FindText方法返回的结果为false
    ts.MoveToLineAndOffset(1, 1);
    bool result = ts.FindText("</mappings>",(int)vsFindOptions.vsFindOptionsMatchWholeWord);
    if (!result)
    {
      if (ts.ActivePoint.Line == 1)
      {     ts.EndOfLine(); ts.NewLine();
      }   string str = "<mappings> " + sb.ToString();   ts.Insert(str); } else {   //需要添加此操作,否则不会替换成功   ts.SelectAll();   ts.ReplacePattern("</mappings>", sb.ToString(), (int)vsFindOptions.vsFindOptionsMatchWholeWord); }
  • 相关阅读:
    ElasticSearch7.6学习使用及问题总结
    phpstorm2020.1破解及使用
    大规模网站开发技术
    备份数据库、恢复数据库、定时
    Centos7系统tmp目录下文件默认保留时长
    linux删除指定文件夹中某个文件除外的其他文件
    python resource模块使用
    python logging 日志轮转文件不删除问题的解决方法
    linux 常用命令快捷键
    shell学习笔记(4)
  • 原文地址:https://www.cnblogs.com/jiangjun0817/p/4106718.html
Copyright © 2020-2023  润新知