• visual studio 插件开发(2) 动态菜单


          这里所谓的动态菜单是指动态指定某些菜单是否显示是否可用,而不是指动态的创建一个新的菜单。就我现在所知,还没有找到通过代码生成菜单而不依赖于vsct的方法。在日常的情形中我们经常能够见到这些需求,比如当用户右击某个解决方案时希望显示“关闭该解决方案”,而在.cs文件上单击时候就不要显示这个选项。下面我们来实现这个需求。
     
    方法一
     
         新建一个带menu项目后,打开vsct文件并在Commands标签之后插入VisibilityConstraints标签。具体的内容如下图所示
     
    你可能已经猜到了这句话的意思就是在没有解决方案打开的情况下,cmdidMyCommand按钮显示。一旦加载了解决方案这个按钮就不可见了。其中的context属性我们可以在vsx1中提到的vsshlids.h文件中找到。同时你也能看到其他你可以使用的context信息。
     
    然后在button标签内插入CommandFlag标签,表明这是一个动态的菜单。
     
    至此,你不需要多写一行c#代码就可以完成菜单的动态显示了。不过这种方法也存在一些缺陷,比如只能使用预定义的条件,比如UICONTEXT_NOSolution不能灵活的自定义其他的条件,而且这种方式只能控制菜单的隐藏与显示,如果我想disable这个菜单就办不到了。
     
    方法二
     
    这个方法弥补了上面说到的一些缺点。具体的做法如下:
    • 和方法一一样,在button标签中添加CommandFlag标签,并设置为DynamicVisibility。
    • 在创建代码
                OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
                if (null != mcs)
                {
                    // Create the command for the menu item.
                    CommandID menuCommandID = new CommandID(GuidList.guidVSPackage1CmdSet, (int)PkgCmdIDList.cmdidMyCommand);
                    OleMenuCommand menuItem = new OleMenuCommand(MenuItemCallback, menuCommandID);
                    menuItem.BeforeQueryStatus += new EventHandler(menuItem_BeforeQueryStatus);
                    mcs.AddCommand(menuItem);
                }
    

      

    这里和原来创建的区别在于OleMenuCommand 对象。原来添加菜单的代码中使用的是MenuCommand对象,而这个OleMenuCommand 对象继承于MenuCommand并实现了一些特殊的功能和事件。比如说我们要使用到的BeforeQueryStatus事件。这个事件的意思就是每次vs进行状态更新的时候都会执行到这个方法,借助于这个机会你可以在该事件中对你的菜单进行动态的设置。事件方法如下:
     
     
      OleMenuCommand menuCommand = sender as OleMenuCommand;
                if (menuCommand != null)
                {
                    IntPtr hierarchyPtr, selectionContainerPtr;
                    uint projectItemId;
                    IVsMultiItemSelect mis;
                    IVsMonitorSelection monitorSelection = (IVsMonitorSelection)Package.GetGlobalService(typeof(SVsShellMonitorSelection));
                    monitorSelection.GetCurrentSelection(out hierarchyPtr, out projectItemId, out mis, out selectionContainerPtr);
    
                    IVsHierarchy hierarchy = Marshal.GetTypedObjectForIUnknown(hierarchyPtr, typeof(IVsHierarchy)) as IVsHierarchy;
                    if (hierarchy != null)
                    {
                        object value;
                        hierarchy.GetProperty(projectItemId, (int)__VSHPROPID.VSHPROPID_Name, out value);
    
                        if (value != null && value.ToString().EndsWith(".cs"))
                        {
                            menuCommand.Visible = true;
                        }
                        else
                        {
                            menuCommand.Visible = false;
                        }
                    }
                }
     
    

      

    这里代码的具体意思不解释了,因为这篇文章的重点不在这里。这段代码的效果就是只有但你在.cs结尾的文件上右击菜单的时候才会见到菜单,否则就不会见到。
    最后,由于vsx的动态加载机制,现在创建的动态菜单并不会显示。需要在package上面添加一个AutoLoad标签,让vs在启动的时候就自动加载我们的插件。这样动态菜单才能正确显示出来。
     
     [ProvideAutoLoad("2c2dd76c-69d1-4889-b82f-b2f2e86c3eeb")]
    

      

    这种方法相比较于上一种给我们提供了更大的灵活性和可控性。所以,在使用的时候肯定一般用第二种了。
     
     
     
  • 相关阅读:
    MFC对话框控件数据提取之DoDataExchange()
    慎用USES_CONVERSION
    Oracle OCP 11G 051(61题版本)答案解析目录
    OCP-1Z0-新051-61题版本-61
    OCP-1Z0-新051-61题版本-60
    OCP-1Z0-新051-61题版本-59
    OCP-1Z0-新051-61题版本-58
    OCP-1Z0-新051-61题版本-57
    OCP-1Z0-新051-61题版本-55
    OCP-1Z0-新051-61题版本-56
  • 原文地址:https://www.cnblogs.com/qianlifeng/p/2281735.html
Copyright © 2020-2023  润新知