2017-05-22 5 views
1

Je souhaite être averti lorsqu'une solution a été complètement chargée. Inspiré par ce answer j'ai essayé d'implémenter IVsSolutionEvents.Comment être averti lorsqu'une solution a été chargée pour un VSPackage?

Quand je charge une solution avec deux projets C#, attendez que le chargement est terminé et, enfin, à proximité Visual Studio 2017, la sortie ne montre que les messages de trace suivants:

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

Est-ce le comportement attendu? Pourquoi OnAfterOpenSolution n'est pas invoqué?

C'est la mise en œuvre du paquet:

[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 
} 
+1

Pourquoi ne pas utiliser UICONTEXT_SolutionExists? –

+0

Le paquet que je développe fournit une fonctionnalité qui n'a de sens que pour les solutions avec plusieurs projets. Je n'étais pas conscient de l'impact de cet argument sur '[ProvideAutoLoad]' sur les événements de solution. Merci pour votre indice. – CodeFox

Répondre

3

Oui, ce par la conception. La raison du comportement observé est que l'événement en question se déclenche avant le chargement de votre paquet. Vous pouvez facilement tester en observant que l'événement se déclenche lorsque vous fermez la solution, puis le rouvrez (après le chargement de votre package). Au deuxième tour, vous verrez le feu de l'événement.

Votre exemple utilise le guide de contexte SolutionHasMultipleProjects, qui garantit que votre package ne sera chargé que si une solution comporte plusieurs projets. La seule façon pour l'EDI de déterminer cela serait de charger la solution, puis de définir le contexte de l'interface utilisateur. Donc, fondamentalement, vous configurez le gestionnaire d'événements un peu trop tard.

Si vous souhaitez recevoir cette notification particulière, vous pouvez enregistrer votre package à charger avec NoSolution_string et SolutionExists_string. Mais c'est un peu mal, car cela force votre paquet à toujours charger (même quand il n'est pas nécessaire), ce qui est une solution moins souhaitable. L'utilisation de SolutionExistsAndFullyLoadedContext pourrait être une meilleure façon de procéder. Lorsque votre paquet est initialement chargé, vous savez que cette condition a été remplie et vous pouvez exécuter votre code de gestionnaire juste avant de revenir à la commande Initialize de votre paquet. Et votre gestionnaire IVsSolutionEvents d'origine sera appelé sur les charges de solution suivantes.

Vous pouvez également envisager d'enregistrer/en utilisant un contexte de l'interface utilisateur basée sur des règles comme décrit ci-dessous:

How to: Use Rule-based UI Context for Visual Studio Extensions

Sincèrement, Ed Dore

+0

Grande explication - Je ne savais pas comment le 'UIContext' pour' [ProvideAutoLoad] 'affecte la gestion des événements. Merci également de mentionner les contextes d'interface utilisateur _rule-based! – CodeFox