在工具栏上动态显示自定义的Visual Studio VSPackage命令

8
假设我们有一个带有工具栏和几个命令的VSPackage。如何以编程方式显示/隐藏工具栏上的其中一个命令?如果您是用户,可以通过自定义工具栏来执行此操作。因此我强烈感觉从代码中也必须有一种方法来实现这一点。
由于我们没有开发AddIn,所以无法使用DTE.Commands.AddNamedCommand(AddInInstance, Name, ButtonText, ToolTip, MSOButton)。
没关系,因为我们仍然可以使用Visual Studio Command Table (.vsct)格式定义我们的命令,并且这是VSPackages的建议方式。
<?xml version="1.0" encoding="utf-8"?>
<CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <Extern href="vsshlids.h" />

  <Commands package="testPackage">

    <Menus>  <!-- Define the menus, toolbars, etc. -->
      <Menu guid="commands" id="toolbar" type="Toolbar">
        <Parent guid="guidSHLMainMenu" id="IDG_VS_BUILD_SOLUTION" />
        <CommandFlag>DefaultDocked</CommandFlag>
        <Strings>
          <ButtonText>TestToolbar</ButtonText>
        </Strings>
      </Menu>
    </Menus>

    <Groups>  <!-- Define the groups for commands -->
      <Group guid="commands" id="toolbarGroup" priority="0x0001">
        <Parent guid="commands" id="toolbar" />
      </Group>
    </Groups>

    <Buttons>  <!-- Define the commands as buttons -->
      <Button guid="commands" id="button0" type="Button">
        <Parent guid="commands" id="toolbarGroup" />
        <CommandFlag>DynamicVisibility</CommandFlag>
        <Strings>
          <ButtonText>TestButton0</ButtonText>
        </Strings>
      </Button>
      <Button guid="commands" id="button1" type="Button">
        <Parent guid="commands" id="toolbarGroup" />
        <CommandFlag>DynamicVisibility</CommandFlag>
        <Strings>
          <ButtonText>TestButton1</ButtonText>
        </Strings>
      </Button>
    </Buttons>

  </Commands>

  <Symbols>
    <GuidSymbol name="testPackage" value="{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}" />

    <GuidSymbol name="commands" value="{EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE}">
      <IDSymbol name="toolbar" value="0x0100" />
      <IDSymbol name="toolbarGroup" value="0x0010" />
      <IDSymbol name="button0" value="0x0000" />
      <IDSymbol name="button1" value="0x0001" />
    </GuidSymbol>
  </Symbols>

</CommandTable>

在后面的C#代码中,您可以设置我们刚刚定义的MenuCommand的不同属性:

System.ComponentModel.Design.MenuCommand menuCommand = <Acquire your menu command>;
menuCommand.Enabled = <enabled>;
menuCommand.Visible = <visible>;
menuCommand.Supported = <supported>;

问题在于,如果将菜单命令放置在工具栏上,则将Visible属性设置为false不会隐藏按钮,只会使其变灰。 (在任何其他菜单上都可以隐藏它。)这是Visual Studio的一个功能,而不是错误。
然而,我需要的正是这个:隐藏Button0。(假设Button0仅在满足某些特殊条件时显示,例如:您的硬盘上的可用空间少于X MB或您安装了某些其他工具,或者只需自己制定条件。)
如果不需要,可以使用AddIn时代的以下技术删除按钮:
EnvDTE.Command button0 = DTE.Commands.Item(commandsGuid, button0CommandId); // Both are the same as in the .vsct file
if (button0 != null)
    button0.Delete();

发现了 Command0 ,但在尝试删除时出现异常:未指定错误(来自 HRESULT 的异常:0x80004005(E_FAIL))。毕竟,它是通过.vsct机制而不是以编程方式创建的,所以这有点说得通。
我已经没有更多想法了。请帮助我找出如何在运行时以编程方式隐藏/显示或添加/删除工具栏按钮。除了.vsct文件之外,是否还有其他定义VSPackage命令的方法?
非常感谢任何帮助。

我遇到了同样的问题。我也尝试使用 vsct 文件中的 <VisibilityConstraints> 部分,但没有成功。你有进展吗? - Przemaas
@Przemaas 我们被那个禁用的(变灰)图标卡住了。因为有比这更高优先级的任务,我们从未想过如何让它消失。 - Shakaron
https://stackoverflow.com/questions/14572226/hiding-a-button-from-a-plugin-toolbar/ - Konstantin S.
1个回答

8
首先,在vsct文件中,您需要对按钮设置DynamicVisibility标志:
  <Button guid="commands" id="button0" priority="0x1001" type="Button">
    <Parent guid="commands" id="toolbarGroup" />
    <CommandFlag>DefaultInvisible</CommandFlag>
    <CommandFlag>DynamicVisibility</CommandFlag>
    <Strings>
      <ButtonText>TestButton1</ButtonText>
    </Strings>
  </Button>

接下来,在重写的Package.Initialize中使用OleMenuCommand类创建命令处理程序,而不是MenuCommand,并订阅BeforeQueryStatus事件,如下所示:
OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (null != mcs)
{
   // Create the command for the menu item.
   CommandID menuCommandID = new CommandID(GuidList.guidToolbarCmdSet, (int)PkgCmdIDList.cmdidButton0);
   var menuItem = new OleMenuCommand(MenuItemCallback, menuCommandID);
   menuItem.BeforeQueryStatus += BeforeQueryStatusCallback;
   mcs.AddCommand(menuItem);
}

现在在 BeforeQueryStatusCallback 中,您可以显示或隐藏您的按钮。
private void BeforeQueryStatusCallback(object sender, EventArgs e)
{
    var cmd = (OleMenuCommand)sender
    cmd.Visible = true;
}

这是完全正确的,如果按钮不在工具栏上。但在我的情况下,它是在工具栏上,因此它不是隐藏的,而是像我在原帖中指出的那样变灰了。你是对的,我应该在项目上包含DynamicVisiblility标志。我已经修复了它。 - Shakaron
错别字 - 行末缺少分号:var cmd = (OleMenuCommand)sender - Greg Trevellick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接