如何在为 VSPackage 加载解决方案时收到通知? [英] How to be notified when a solution has been loaded for a VSPackage?

查看:29
本文介绍了如何在为 VSPackage 加载解决方案时收到通知?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望在完全加载解决方案时收到通知.受此 answer 的启发,我尝试实施 IVsSolutionEvents.

I would like to be notified when a solution has been completely loaded. Inspired by this answer I tried implementing IVsSolutionEvents.

当我加载包含两个 C# 项目的解决方案时,等待加载完成并最终关闭 Visual Studio 2017,输出仅显示以下跟踪消息:

When I load a solution with two C# projects, wait until loading has finished and finally close Visual Studio 2017, the output shows only the following trace messages:

VSTestPackage1: OnAfterOpenProject
VSTestPackage1: OnQueryCloseSolution
VSTestPackage1: OnQueryCloseProject
VSTestPackage1: OnQueryCloseProject
VSTestPackage1: OnBeforeCloseSolution
VSTestPackage1: OnQueryCloseProject
VSTestPackage1: OnBeforeCloseProject
VSTestPackage1: OnQueryCloseProject
VSTestPackage1: OnBeforeCloseProject
VSTestPackage1: OnAfterCloseSolution

这是预期的行为吗?为什么 OnAfterOpenSolution 没有被调用?

Is this the expected behavior? Why is OnAfterOpenSolution not being invoked?

这是包的实现:

[PackageRegistration(UseManagedResourcesOnly = true)]
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
[Guid(PackageGuidString)]
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly",
    Justification = "pkgdef, VS and vsixmanifest are valid VS terms")]
[ProvideAutoLoad(VSConstants.UICONTEXT.SolutionHasMultipleProjects_string)]
public sealed class VSPackage1 : Package, IVsSolutionEvents
{
    public const string PackageGuidString = "2e655097-9510-4cf8-b9d4-ceeacebbaf3c";

    private DTE _dte;
    private uint _hSolutionEvents = uint.MaxValue;
    private IVsSolution _solution;

    /// <summary>
    ///     Initialization of the package; this method is called right after the package is sited, so this is the place
    ///     where you can put all the initialization code that rely on services provided by VisualStudio.
    /// </summary>
    protected override void Initialize()
    {
        base.Initialize();

        _dte = (DTE) GetService(typeof(DTE));

        AdviseSolutionEvents();
    }

    protected override void Dispose(bool disposing)
    {
        UnadviseSolutionEvents();

        base.Dispose(disposing);
    }

    private void AdviseSolutionEvents()
    {
        UnadviseSolutionEvents();

        _solution = GetService(typeof(SVsSolution)) as IVsSolution;

        _solution?.AdviseSolutionEvents(this, out _hSolutionEvents);
    }

    private void UnadviseSolutionEvents()
    {
        if (_solution == null) return;
        if (_hSolutionEvents != uint.MaxValue)
        {
            _solution.UnadviseSolutionEvents(_hSolutionEvents);
            _hSolutionEvents = uint.MaxValue;
        }

        _solution = null;
    }

    #region Implementation of IVsSolutionEvents

    int IVsSolutionEvents.OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded)
    {
        Trace.WriteLine("OnAfterOpenProject", "VSTestPackage1");
        return VSConstants.S_OK;
    }

    int IVsSolutionEvents.OnQueryCloseProject(IVsHierarchy pHierarchy, int fRemoving, ref int pfCancel)
    {
        Trace.WriteLine("OnQueryCloseProject", "VSTestPackage1");
        return VSConstants.S_OK;
    }

    int IVsSolutionEvents.OnBeforeCloseProject(IVsHierarchy pHierarchy, int fRemoved)
    {
        Trace.WriteLine("OnBeforeCloseProject", "VSTestPackage1");
        return VSConstants.S_OK;
    }

    int IVsSolutionEvents.OnAfterLoadProject(IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy)
    {
        Trace.WriteLine("OnAfterLoadProject", "VSTestPackage1");
        return VSConstants.S_OK;
    }

    int IVsSolutionEvents.OnQueryUnloadProject(IVsHierarchy pRealHierarchy, ref int pfCancel)
    {
        Trace.WriteLine("OnQueryUnloadProject", "VSTestPackage1");
        return VSConstants.S_OK;
    }

    int IVsSolutionEvents.OnBeforeUnloadProject(IVsHierarchy pRealHierarchy, IVsHierarchy pStubHierarchy)
    {
        Trace.WriteLine("OnBeforeUnloadProject", "VSTestPackage1");
        return VSConstants.S_OK;
    }

    int IVsSolutionEvents.OnAfterOpenSolution(object pUnkReserved, int fNewSolution)
    {
        Trace.WriteLine("OnAfterOpenSolution", "VSTestPackage1");
        return VSConstants.S_OK;
    }

    int IVsSolutionEvents.OnQueryCloseSolution(object pUnkReserved, ref int pfCancel)
    {
        Trace.WriteLine("OnQueryCloseSolution", "VSTestPackage1");
        return VSConstants.S_OK;
    }

    int IVsSolutionEvents.OnBeforeCloseSolution(object pUnkReserved)
    {
        Trace.WriteLine("OnBeforeCloseSolution", "VSTestPackage1");
        return VSConstants.S_OK;
    }

    int IVsSolutionEvents.OnAfterCloseSolution(object pUnkReserved)
    {
        Trace.WriteLine("OnAfterCloseSolution", "VSTestPackage1");
        return VSConstants.S_OK;
    }

    #endregion
}

推荐答案

是的,这是设计使然.观察到的行为的原因是因为有问题的事件在您的包加载之前触发.您可以通过观察事件是否触发来轻松测试,当您关闭解决方案时,然后重新打开它(在您的包加载后).在第 2 周,您将看到事件发生.

Yes, this by design. The reason for the observed behavior, is because the event in question is firing before your package is loaded. You can readily test by observing that the event does fire, when you close the solution, and then reopen it (after your package is loaded). On the 2nd go around, you'll see the event fire.

您的示例使用了 SolutionHasMultipleProjects 上下文 guid,它确保您的包仅在一个解决方案具有多个项目时加载.IDE 确定这一点的唯一方法是首先加载解决方案,然后设置 UI 上下文.所以基本上,您设置事件处理程序有点太晚了.

Your example is using the SolutionHasMultipleProjects context guid, which ensures your package will only load if a solution has multiple projects. The only way for the IDE to determine that, would be to first have the solution load, and then set the UI context. So basically, you're setting up the event handler just a little too late.

如果您想确保收到该特定通知,您可以注册您的包以使用 NoSolution_string 和 SolutionExists_string 加载.但这有点邪恶,因为这会强制您的包始终加载(即使不需要它),这是一个不太理想的解决方案.

If you want to ensure you receive that particular notification, you can register your package to load with NoSolution_string and SolutionExists_string. But that's somewhat evil, as this forces your package to always load (even when it isn't needed), which is a less that desirable solution.

使用 SolutionExistsAndFullyLoadedContext 可能是更好的方法.当您的包最初加载时,您将知道条件已满足,并且您可以在从包的 Initialize 覆盖返回之前运行您的处理程序代码.并且您的原始 IVsSolutionEvents 处理程序将在后续解决方案加载时调用.

Using SolutionExistsAndFullyLoadedContext might be a better way to go. When your package is initially loaded, you'll know that condition has been met, and you can run your handler code just before returning from your package's Initialize override. And your original IVsSolutionEvents handler will be invoked on subsequent solution loads.

您可能还想考虑注册/使用基于规则的 UI 上下文,如下所述:

You might also want to consider registering/using a rule-based UI context as described below:

如何:为 Visual Studio 扩展使用基于规则的 UI 上下文

真诚的,埃德多尔

这篇关于如何在为 VSPackage 加载解决方案时收到通知?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆