2011-10-19 12 views
13

'dan çözüm ve proje olaylarına nasıl abone olurum Visual Studio için bir VSPackage aracılığıyla bir dil hizmeti geliştiriyorum. Çözüm projelerinden dosyalar eklendiğinde/kaldırıldığında, ayrıştırma verilerimi güncellemem gerekiyor.Bir VSPackage

Çözüm ve proje etkinliklerine abone olmak istiyorum.

Aşağıdakileri denedim, ancak çözümlere proje eklediğimde/kaldırırken veya projelere öğe eklediğimde/kaldırıldığında bu olaylardan hiçbiri işe yaramıyor.

DTE dte = (DTE)languageService.GetService(typeof(DTE)); 
if (dte == null) 
    return; 

((Events2)dte.Events).SolutionEvents.ProjectAdded += SolutionEvents_ProjectAdded; 
((Events2)dte.Events).SolutionEvents.ProjectRemoved += SolutionEvents_ProjectRemoved; 
((Events2)dte.Events).ProjectItemsEvents.ItemAdded += ProjectItemsEvents_ItemAdded; 
((Events2)dte.Events).ProjectItemsEvents.ItemRemoved += ProjectItemsEvents_ItemRemoved; 

Bu olaylara bir VSPackage'dan abone olmanın en iyi yolu nedir? Herhangi bir yardım takdir!

cevap

8

DTE Olayları biraz garip, COM Interop'un onları canlı tutmasını bilmesi için olay kaynağı nesnesini (Çözümünüzde SolutionEvents ve ProjectItemEvents) önbelleğe almanız gerekir. Bu @ üzerinde

public class MyClass 
{ 
    SolutionEvents solutionEvents; 

    public void ConnectToEvents() 
    { 
     solutionEvents = ((Events2)dte.Events).SolutionEvents; 
     solutionEvents.ProjectAdded += OnProjectAdded; 
     // Etc 
    } 
} 

Daha http://msdn.microsoft.com/en-us/library/ms165650(v=vs.80).aspx

12

Alternatif çok daha iyi olayları

[PackageRegistration(UseManagedResourcesOnly = true)] 
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] 
// add these 2 Annotations to execute Initialize() immediately when a project is loaded 
[ProvideAutoLoad(VSConstants.UICONTEXT.SolutionHasSingleProject_string)] 
[ProvideAutoLoad(VSConstants.UICONTEXT.SolutionHasMultipleProjects_string)] 
[Guid(GuidList.XYZ)] 
public sealed class UnityProjectUpdateHandlerPackage : Package, IVsSolutionEvents3 
{ 
    private DTE _dte; 
    private IVsSolution solution = null; 
    private uint _hSolutionEvents = uint.MaxValue; 

    protected override void Initialize() 
    { 
     Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString())); 
     base.Initialize(); 

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

     AdviseSolutionEvents(); 
    } 

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

     base.Dispose(disposing); 
    } 

    private void AdviseSolutionEvents() 
    { 
     UnadviseSolutionEvents(); 

     solution = this.GetService(typeof(SVsSolution)) as IVsSolution; 

     if (solution != null) 
     { 
      solution.AdviseSolutionEvents(this, out _hSolutionEvents); 
     } 
    } 

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

      solution = null; 
     } 
    } 

    private Project[] GetProjects() 
    { 
     return _dte.Solution.Projects 
      .Cast<Project>() 
      .Select(x => ((VSProject) x.Object).Project) 
      .ToArray(); 
    } 

    public int OnAfterLoadProject(IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy) 
    { 
     // Do something 
     return VSConstants.S_OK; 
    } 

    public int OnAfterOpenSolution(object pUnkReserved, int fNewSolution) 
    { 
     foreach (var project in GetProjects()) 
      ; // Do something 

     return VSConstants.S_OK; 
    } 

    public int OnBeforeUnloadProject(IVsHierarchy pRealHierarchy, IVsHierarchy pStubHierarchy) 
    { 
     // Do something 
     return VSConstants.S_OK; 
    } 

    public int OnAfterCloseSolution(object pUnkReserved) 
    { return VSConstants.S_OK; } 

    public int OnAfterClosingChildren(IVsHierarchy pHierarchy) 
    { return VSConstants.S_OK; } 

    public int OnAfterMergeSolution(object pUnkReserved) 
    { return VSConstants.S_OK; } 

    public int OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded) 
    { return VSConstants.S_OK; } 

    public int OnAfterOpeningChildren(IVsHierarchy pHierarchy) 
    { return VSConstants.S_OK; } 

    public int OnBeforeCloseProject(IVsHierarchy pHierarchy, int fRemoved) 
    { return VSConstants.S_OK; } 

    public int OnBeforeClosingChildren(IVsHierarchy pHierarchy) 
    { return VSConstants.S_OK; } 

    public int OnBeforeOpeningChildren(IVsHierarchy pHierarchy) 
    { return VSConstants.S_OK; } 

    public int OnBeforeCloseSolution(object pUnkReserved) 
    { return VSConstants.S_OK; } 

    public int OnQueryCloseProject(IVsHierarchy pHierarchy, int fRemoving, ref int pfCancel) 
    { return VSConstants.S_OK; } 

    public int OnQueryCloseSolution(object pUnkReserved, ref int pfCancel) 
    { return VSConstants.S_OK; } 

    public int OnQueryUnloadProject(IVsHierarchy pRealHierarchy, ref int pfCancel) 
    { return VSConstants.S_OK; } 
} 
+0

Initialize() 'de' _hSolutionEvents' nedir? –

+0

Haklısınız, kodu güncellediniz! 'UnadviseSolutionEvents' için gerekli olan '_hSolutionEvents' üzerinde başka bir düşünce vardı ve yeni kodu da ekledim. En iyi DevTool için eklentileri yapmakla ilgili fazla bilgi yok diye bir utanç var ... – FooBarTheLittle

5
açıklanan sorunu tam olarak geri kalanı için aynı olmasına rağmen

(ProjectAdded olaya odağı Lets vardır IVsSolutionEvents3, kullanabilirsiniz olaylar.

Gösterilen kod örneği, ProjectAdded olayına ilişkin SolutionEvents_ProjectAdded işleyicisini kaydetmeye çalışır. Ancak, olayı açığa çıkaran SolutionEvents nesnesinin, sarmalama yönteminin kapatılmasıyla sınırlı ömür boyu kapsamı vardır (imzasını göstermediniz - buna Connect diyelim). denetim akışı o kapsamını ayrıldıktan sonra onun olay asla denir böylece yerel nesne zaten, çöp toplanan olmuştur:

Kırık kodu:

public class Connector 
{ 
    public void Connect() 
    { 
     ((Events2)dte.Events).SolutionEvents.ProjectAdded += SolutionEvents_ProjectAdded; 
    } 
    void SolutionEvents_ProjectAdded() 
    { 
     // callback is dead 
    } 
} 

düzeltmek için tek ihtiyacınız SolutionEvents atamak Yaşamı SolutionEvents_ProjectAdded işleyiciye yayılmış bazı değişkenlere nesne - örn. tüm sarma sınıfının üzerinde. Aşağıdaki örnekte, kapsamı bütün türe (en Connector diyelim) üzerinden uzanır ve işleyici bu tür ömrü boyunca erişilebilir olmasını sağlar:

Sabit kod:

public class Connector 
{ 
    SolutionEvents _solutionEvents; 
    public void Connect() 
    { 
     _solutionEvents = ((Events2)dte.Events).SolutionEvents; 
     _solutionEvents.ProjectAdded += SolutionEvents_ProjectAdded; 
    } 
    void SolutionEvents_ProjectAdded() 
    { 
     // callback works 
    } 
} 

için

programlama olay işleyicileri ortak bir hata ağırlık ilan edilmiş bir nesneye olay işleyicisi bağlanan: Scoping Variables Appropriately in Event Handlers - daha kesin, bu MSDN referans kontrol Etkinliği ele almak için çok sınırlı bir kapsam . Nesnenin, yalnızca olayın bir olay işleyicisi olarak geri arama yöntemini bağlayan işlevi değil, aynı zamanda olayın gerçekten işlendiği geri arama yönteminin kendisi üzerinden bağlanan bir yaşam olması gerekir.Aksi takdirde, nesnesi kapsam dışıysa ve artık geri arama yönteminde tanımlanmamışsa, geri arama yöntemi çağrılmaz ve olay istenildiği gibi işlenmez.