命令实现

若要在 VSPackage 中实现命令,必须执行以下任务:

  1. .vsct 文件中,设置一个命令组,然后将该命令添加到其中。 有关详细信息,请参阅 Visual Studio 命令表 (.vsct) 文件

  2. 将命令注册到 Visual Studio。

  3. 实现命令。

以下部分介绍如何注册和实现命令。

向 Visual Studio 注册命令

如果命令显示在菜单上,则必须将它 ProvideMenuResourceAttribute 添加到 VSPackage,并将其用作菜单的名称或其资源 ID 的值。

[ProvideMenuResource("Menus.ctmenu", 1)]
public sealed class MyPackage : Package
{
    // ...
}

此外,还必须将命令注册到 .OleMenuCommandService 如果 VSPackage 派生自 Package,则可以使用GetService此方法获取此服务。

OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (mcs is not null)
{
    // Create the command for the menu item.
    CommandID menuCommandID = new CommandID(guidCommandGroup, myCommandID);
    MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
    mcs.AddCommand(menuItem);
}

实现命令

可通过多种方式实现命令。 如果需要静态菜单命令(即始终以相同方式显示命令)在同一菜单上,请使用 MenuCommand 上一部分中的示例所示创建命令。 若要创建静态命令,必须提供负责执行命令的事件处理程序。 由于命令始终处于启用状态且可见,因此无需将其状态提供给 Visual Studio。 如果要根据特定条件更改命令的状态,可以将命令创建为类的 OleMenuCommand 实例,并在其构造函数中提供事件处理程序来执行命令,并在 QueryStatus 命令状态发生更改时通知 Visual Studio。 还可以作为命令类的一部分实现 IOleCommandTarget ,或者,如果在项目中提供命令,则可以实现 IVsHierarchy 。 这两个接口和 OleMenuCommand 类都具有通知 Visual Studio 命令状态更改的方法,以及提供命令执行的其他方法。

将命令添加到命令服务时,它将成为命令链之一。 为命令实现状态通知和执行方法时,请注意仅提供该特定命令,并将所有其他情况传递到链中的其他命令。 如果无法传递命令(通常通过返回 OLECMDERR_E_NOTSUPPORTED),Visual Studio 可能会停止正常工作。

QueryStatus 方法

如果要实现QueryStatus该方法或QueryStatusCommand方法,检查命令所属的命令集的 GUID 和命令的 ID。 请遵循这些指导:

  • 如果无法识别 GUID,则任一方法的实现必须返回 OLECMDERR_E_UNKNOWNGROUP

  • 如果任一方法的实现识别 GUID 但尚未实现命令,则该方法应返回 OLECMDERR_E_NOTSUPPORTED

  • 如果任一方法的实现同时识别 GUID 和命令,则该方法应使用以下OLECMDF标志设置每个命令(在prgCmds参数中)的命令标志字段:

    • OLECMDF_SUPPORTED:支持该命令。

    • OLECMDF_INVISIBLE:该命令不应可见。

    • OLECMDF_LATCHED:该命令已打开并显示为已检查。

    • OLECMDF_ENABLED:已启用该命令。

    • OLECMDF_DEFHIDEONCTXTMENU:如果命令出现在快捷菜单上,则应隐藏该命令。

    • OLECMDF_NINCHED:命令是菜单控制器,未启用,但其下拉菜单列表不为空,仍可用。 (此标志很少使用。

  • 如果使用标志在 .vsct 文件中 TextChanges 定义了该命令,请设置以下参数:

    • rgwz 参数的 pCmdText 元素设置为命令的新文本。

    • cwActual 参数的 pCmdText 元素设置为命令字符串的大小。

此外,请确保当前上下文不是自动化函数,除非命令专门用于处理自动化函数。

若要指示你支持特定命令,请返回 S_OK。 对于所有其他命令,返回 OLECMDERR_E_NOTSUPPORTED

在下面的示例中,该方法 QueryStatus 首先确保上下文不是自动化函数,然后找到正确的命令集 GUID 和命令 ID。 命令本身设置为启用和支持。 不支持其他任何命令。

public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
{
    if (!VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider))
    {
        if (pguidCmdGroup == VSConstants.VSStd2K && cCmds > 0)
        {
            // make the Right command visible
            if ((uint)prgCmds[0].cmdID == (uint)VSConstants.VSStd2KCmdID.RIGHT)
            {
                prgCmds[0].cmdf = (int)Microsoft.VisualStudio.OLE.Interop.Constants.MSOCMDF_ENABLED | (int)Microsoft.VisualStudio.OLE.Interop.Constants.MSOCMDF_SUPPORTED;
                return VSConstants.S_OK;
            }
        }
    }
    return Constants.OLECMDERR_E_NOTSUPPORTED;
}

执行方法

方法 Exec 的实现类似于方法的 QueryStatus 实现。 首先,请确保上下文不是自动化函数。 然后,测试 GUID 和命令 ID。 如果无法识别 GUID 或命令 ID,则返回 OLECMDERR_E_NOTSUPPORTED

若要处理命令,请执行该命令,并在执行成功时返回 S_OK 。 命令负责错误检测和通知;因此,如果执行失败,则返回错误代码。 以下示例演示如何实现执行方法。

public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
{
    if (!VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider))
    {
        if (pguidCmdGroup == VSConstants.GUID_VSStandardCommandSet97)
        {
             if (nCmdID == (uint)VSConstants.VSStd2KCmdID.RIGHT)
            {
                // execute the command
                return VSConstants.S_OK;
            }
        }
    }
    return Constants.OLECMDERR_E_NOTSUPPORTED;
}