You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Visual Studio扩展UI上下文规则失效:右键菜单无法按需显示

问题:VS扩展上下文菜单无法仅在JSON文件中显示

我正在开发一款Visual Studio扩展,用于实现JSON文件的常规操作。目标是仅在解决方案资源管理器中右键点击JSON文件时显示对应的上下文菜单项。目前命令可正常运行,但会显示在所有文件上;即使参考微软官网的.config/.cs文件示例配置,问题仍存在。

现有配置如下:

Package类定义

[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
[Guid(QuickSwapSettingsExtensionPackage.PackageGuidString)]
[ProvideMenuResource("Menus.ctmenu", 1)]
[ProvideAutoLoad(UIContextGuid, PackageAutoLoadFlags.BackgroundLoad)]
[ProvideUIContextRule(UIContextGuid,
    name: "Apply only to JSON files",
    expression: "DotConfig",
    termNames: new[] { "DotConfig" },
    termValues: new[] { "HierSingleSelectionName:.config$" })]
public sealed class QuickSwapSettingsExtensionPackage : AsyncPackage
{
    public const string PackageGuidString = "d6069cfa-a050-490c-bf8a-5ddb780e204d";

    public const string UIContextGuid = "2cfcc18c-f6b5-418a-8531-2b8f3bf53cf5";

    ...
}

VSCT文件按钮定义

<Commands package="guidQuickSwapSettingsExtensionPackage">
    <Groups>
        <Group guid="guidQuickSwapSettingsExtensionPackageCmdSet" id="MyMenuGroup" priority="0x0600">
            <Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_ITEMNODE"/>
        </Group>
    </Groups>

    <Buttons>
        <Button guid="guidQuickSwapSettingsExtensionPackageCmdSet" id="SwapSettingsCommandId" priority="0x0100" type="Button">
            <Parent guid="guidQuickSwapSettingsExtensionPackageCmdSet" id="MyMenuGroup" />
            <Icon guid="guidImages" id="bmpPic1" />
            <CommandFlag>DynamicVisibility</CommandFlag>
            <Strings>
                <ButtonText>Invoke SwapSettingsCommand</ButtonText>
            </Strings>
        </Button>
    </Buttons>
    <Bitmaps>
        <Bitmap guid="guidImages" href="Resources\SwapSettingsCommand.png" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows, bmpPicStrikethrough"/>
    </Bitmaps>
</Commands>

可见性约束

<VisibilityConstraints>
    <VisibilityItem guid="guidQuickSwapSettingsExtensionPackageCmdSet" id="SwapSettingsCommandId" context="UIContextGuid"/>
</VisibilityConstraints>

GUID符号定义

<Symbols>
    <!-- This is the package guid. -->
    <GuidSymbol name="guidQuickSwapSettingsExtensionPackage" value="{d6069cfa-a050-490c-bf8a-5ddb780e204d}" />

    <GuidSymbol name="UIContextGuid" value="{2cfcc18c-f6b5-418a-8531-2b8f3bf53cf5}" />
</Symbols>

实际问题表现:扩展启动后右键非config文件时菜单项不显示;但右键过config文件后,菜单项会永久显示在所有文件上,不会随选中文件切换而消失。需要菜单项仅在选中JSON文件时显示(或对其他文件禁用)。


解决方案

问题出在ProvideUIContextRule的规则设计和UI上下文的自动加载逻辑上,以下是修复步骤:

1. 修正UI上下文规则,针对JSON文件匹配

将原有的.config后缀匹配改为.json,同时添加上下文失效条件,确保选中非JSON文件时UI上下文能自动关闭:

[ProvideUIContextRule(UIContextGuid,
    name: "Apply only to JSON files",
    expression: "DotJson",
    termNames: new[] { "DotJson" },
    termValues: new[] { "HierSingleSelectionName:.json$" },
    // 添加失效条件:当选中的文件不是.json时,上下文关闭
    inverseExpression: "NotDotJson",
    inverseTermNames: new[] { "NotDotJson" },
    inverseTermValues: new[] { "HierSingleSelectionName:^(?!.*\\.json$).*$" })]

2. 移除ProvideAutoLoad特性

ProvideAutoLoad会让包在UI上下文激活后一直保持加载状态,导致上下文规则无法正确重置。移除该特性,让VS按需加载包:

// 移除这一行
// [ProvideAutoLoad(UIContextGuid, PackageAutoLoadFlags.BackgroundLoad)]

3. 为命令组添加动态可见性约束

除了按钮的可见性,还需要给菜单组添加相同的上下文约束,避免组被永久激活:
在VSCT的VisibilityConstraints中添加组的约束:

<VisibilityConstraints>
    <VisibilityItem guid="guidQuickSwapSettingsExtensionPackageCmdSet" id="MyMenuGroup" context="UIContextGuid"/>
    <VisibilityItem guid="guidQuickSwapSettingsExtensionPackageCmdSet" id="SwapSettingsCommandId" context="UIContextGuid"/>
</VisibilityConstraints>

4. 确保命令实现状态实时更新

如果你的命令类继承自BaseCommand,重写QueryStatus方法,主动检查当前选中文件的类型,确保命令状态实时更新:

protected override void QueryStatus(OleMenuCommand command)
{
    // 获取当前选中的项目
    var selectedItem = GetSelectedItem();
    bool isJsonFile = selectedItem?.Name.EndsWith(".json", StringComparison.OrdinalIgnoreCase) ?? false;
    
    command.Visible = isJsonFile;
    command.Enabled = isJsonFile;
}

关键原理

UI上下文规则默认是累积激活的,一旦匹配过一次就不会自动失效,必须通过inverseExpression明确指定失效条件。同时,ProvideAutoLoad会让包持续加载,干扰上下文的动态切换逻辑,移除后VS会根据上下文状态自动管理包的加载与卸载。


内容的提问来源于stack exchange,提问作者Dominick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 13:14:58