2011-10-19 30 views
13

Tôi đang phát triển dịch vụ ngôn ngữ cho Visual Studio thông qua VSPackage. Tôi cần cập nhật dữ liệu phân tích cú pháp của mình bất cứ khi nào tệp được thêm/xóa khỏi dự án của giải pháp.Làm cách nào để đăng ký các sự kiện giải pháp và dự án từ VSPackage

Tôi muốn đăng ký các sự kiện giải pháp và dự án.

Tôi đã thử như sau, nhưng không có sự kiện nào trong số này xảy ra khi tôi thêm/xóa dự án vào giải pháp hoặc thêm/xóa mục vào dự án.

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; 

Cách tốt nhất để đăng ký các sự kiện này từ VSPackage là gì? Bất kỳ trợ giúp nào được đánh giá cao!

Trả lời

8

Sự kiện DTE hơi lạ, bạn cần lưu bộ nhớ cache đối tượng nguồn sự kiện (SolutionEvents và ProjectItemEvents trong trường hợp của bạn), để COM Interop biết cách giữ cho chúng hoạt động.

public class MyClass 
{ 
    SolutionEvents solutionEvents; 

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

Thông tin thêm về @ này http://msdn.microsoft.com/en-us/library/ms165650(v=vs.80).aspx

12

Hoặc bạn có thể sử dụng IVsSolutionEvents3, trong đó có sự kiện tốt hơn nhiều

[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

'_hSolutionEvents' trong' Initialize() 'là gì? –

+0

Bạn nói đúng, đã cập nhật mã! Đã có một suy nghĩ về '_hSolutionEvents' đó là cần thiết cho' UnadviseSolutionEvents' và thêm mã mới, quá. Thật đáng tiếc là không có nhiều thông tin về việc tạo plugin cho DevTool tốt nhất ... – FooBarTheLittle

5

Hãy tập trung vào ProjectAdded sự kiện (mặc dù vấn đề được mô tả là giống hệt nhau cho phần còn lại của các sự kiện).

Mẫu mã bạn đã hiển thị các nỗ lực để đăng ký trình xử lý SolutionEvents_ProjectAdded cho sự kiện ProjectAdded. Tuy nhiên, đối tượng SolutionEvents phơi bày sự kiện, có phạm vi thời gian giới hạn cho việc đóng gói phương thức gói của nó (bạn chưa hiển thị chữ ký của nó - hãy gọi nó là Connect). Sau khi kiểm soát dòng chảy đã rời khỏi phạm vi đó, đối tượng địa phương đã được thu gom rác thải, vì vậy sự kiện của nó không bao giờ được gọi là:

đang bị hỏng:

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

Để khắc phục điều đó, bạn cần phải gán các SolutionEvents đối tượng cho một số biến, có thời gian tồn tại trên bộ xử lý SolutionEvents_ProjectAdded - ví dụ trên toàn bộ lớp học. Trong ví dụ dưới đây, phạm vi mở rộng trên toàn bộ loại (chúng ta hãy gọi nó Connector), và đảm bảo rằng xử lý có thể truy cập trong thời gian tồn tại của loại hình đó:

Cố định mã:

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

Để được chính xác hơn, kiểm tra thông tin này MSDN - Scoping Variables Appropriately in Event Handlers:

một sai lầm phổ biến trong các xử lý sự kiện lập trình được kết nối xử lý sự kiện đến một đối tượng mà đã được tuyên bố w ith phạm vi quá giới hạn cho mục đích xử lý sự kiện. Các đối tượng phải có một cuộc sống mà không chỉ vượt qua chức năng kết nối gọi lại phương pháp như một xử lý sự kiện của đối tượng, mà còn trên các phương pháp gọi lại chính nó, nơi sự kiện này thực sự được xử lý.Nếu không, nếu đối tượng nằm ngoài phạm vi và không còn được xác định trong phương thức gọi lại , phương thức gọi lại không được gọi và sự kiện không được xử lý như mong muốn.

Các vấn đề liên quan