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

Visual Studio 2017扩展:工具栏隐藏后仍接收IVsSelectionEvents事件

解决Visual Studio扩展工具栏隐藏后仍接收IVsSelectionEvents的问题

我来帮你搞定这个头疼的问题——工具栏隐藏后还持续收到选择事件,核心就是没法及时感知工具栏的状态变化来动态调整订阅。这里给你两个靠谱的解决方案:

方案一:直接监听CommandBar的可见性变化

VS的工具栏本质是基于Office的CommandBar模型,你可以在创建工具栏的时候,给它加个VisibleChanged事件监听,就能精准捕获显示/隐藏的时机:

  1. 先拿到你的工具栏对应的CommandBar实例(一般在Package的初始化代码里):
var commandService = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
// 替换成你自己的工具栏命令ID和命令集GUID
CommandBar toolbar = commandService.GetCommandBar(new Guid("你的命令集GUID"), 你的工具栏CmdId);
  1. 订阅它的VisibleChanged事件:
toolbar.VisibleChanged += Toolbar_VisibleChanged;
  1. 在事件处理里动态管理选择事件的订阅:
private uint _selectionCookie; // 保存订阅的Cookie,用于取消订阅

private void Toolbar_VisibleChanged(object sender, EventArgs e)
{
    var toolbar = sender as CommandBar;
    var monitorSelection = GetService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection;
    
    if (toolbar.Visible)
    {
        // 工具栏显示时,订阅选择事件
        monitorSelection.AdviseSelectionEvents(你的SelectionEvents实现类实例, out _selectionCookie);
    }
    else
    {
        // 工具栏隐藏时,立刻取消订阅
        monitorSelection.UnadviseSelectionEvents(_selectionCookie);
    }
}

方案二:通过广播消息监听全局状态变化

如果拿不到CommandBar实例,还可以通过VS的广播消息机制来监听工具栏的状态变更:

  1. 先实现IVsBroadcastMessageEvents接口来处理广播消息:
public class ToolbarVisibilityListener : IVsBroadcastMessageEvents
{
    private readonly IVsMonitorSelection _monitorSelection;
    private readonly IVsSelectionEvents _selectionHandler;
    private uint _selectionCookie;

    public ToolbarVisibilityListener(IVsMonitorSelection monitorSelection, IVsSelectionEvents selectionHandler)
    {
        _monitorSelection = monitorSelection;
        _selectionHandler = selectionHandler;
    }

    public int OnBroadcastMessage(uint msg, IntPtr wParam, IntPtr lParam)
    {
        // 监听工具栏可见性变更的内部消息
        if (msg == (uint)VSConstants.VSSPROPID_ToolbarVisible)
        {
            // 这里可以根据wParam判断是否是你的工具栏(wParam是工具栏的命令ID)
            if (wParam == (IntPtr)你的工具栏CmdId)
            {
                bool isVisible = Marshal.ReadInt32(lParam) != 0;
                if (isVisible)
                {
                    _monitorSelection.AdviseSelectionEvents(_selectionHandler, out _selectionCookie);
                }
                else
                {
                    _monitorSelection.UnadviseSelectionEvents(_selectionCookie);
                }
            }
        }
        return VSConstants.S_OK;
    }
}
  1. 在Package里订阅这个广播事件:
private uint _broadcastCookie;

protected override void Initialize()
{
    base.Initialize();
    var shell = GetService(typeof(SVsUIShell)) as IVsUIShell;
    var monitorSelection = GetService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection;
    shell.AdviseBroadcastMessageEvents(new ToolbarVisibilityListener(monitorSelection, 你的SelectionEvents实例), out _broadcastCookie);
}

额外提醒

  • 记得在Package销毁时(比如重写Dispose方法),把所有订阅的Cookie都取消掉,避免内存泄漏。
  • 方案一的CommandBar获取要确保工具栏已经被正确创建,建议在Initialize方法的后半段执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:27:13