2017-10-10 320 views
1

我正在開發一個Visual Studio擴展,其中一個實現的命令只有在活動文檔是文本文檔時纔可用(例如Visual Studio的「切換書籤」)。問題是,我無法弄清楚如何判斷這種情況。如何判斷活動文檔是否爲文本文檔?

現在我有一半的工作解決方案。在包的Initialize方法予訂閱DTE的WindowActivated事件,然後每當被激活的窗口餘檢查窗口DocumentData屬性是TextDocument類型:

protected override void Initialize() 
{ 
    base.Initialize(); 

    var dte = Package.GetGlobalService(typeof(EnvDTE.DTE)) as EnvDTE.DTE; 
    dte.Events.WindowEvents.WindowActivated += WindowEventsOnWindowActivated; 

    //More initialization here... 
} 

//This is checked from command's BeforeQueryStatus 
public bool ActiveDocumentIsText { get; private set; } = false; 

private void WindowEventsOnWindowActivated(Window gotFocus, Window lostFocus) 
{ 
    if (gotFocus.Kind != "Document")     
     return; //It's not a document (e.g. it's a tool window) 

    TextDocument textDoc = gotFocus.DocumentData as TextDocument; 
    ActiveDocumentIsText = textDoc != null; 
} 

這種方法的問題是,1)Window.DocumentData is documented as ".NET Framework internal use only",和2)當在設計模式下打開具有代碼視圖和設計視圖的文檔(例如.visxmanifest文件)時,這會產生誤報。

我曾嘗試使用IVsTextManager.GetActiveView爲好,但這是返回最後活動文本視圖中打開 - 所以,如果我打開一個txt文件,然後.png文件,它的.txt文件返回數據,即使如果它不再是活動文檔。

那麼,如何檢查活動文檔是文本文檔還是可以有設計者的文檔的代碼視圖......並且如果可能,不使用「無證」類/成員?

更新:我發現了一個稍微好一點的解決方案。裏面的窗口激活處理程序:

ActiveDocumentIsText = gotFocus.Document.Object("TextDocument") != null; 

至少this one is properly documented,但我仍然有設計師誤報的問題。

回答

0

我終於明白了。這有點棘手,但它的工作原理是100%「合法」。這裏是配方:

1-使包類實現IVsRunningDocTableEvents。使所有的方法只是return VSConstants.S_OK;

2-以下字段和以下輔助方法添加到包類:

private IVsRunningDocumentTable runningDocumentTable; 

private bool DocIsOpenInLogicalView(string path, Guid logicalView, out IVsWindowFrame windowFrame) 
{ 
    return VsShellUtilities.IsDocumentOpen(
     this, 
     path, 
     VSConstants.LOGVIEWID_TextView, 
     out var dummyHierarchy2, out var dummyItemId2, 
     out windowFrame); 
} 

3-添加以下到Initialize方法包類的:

runningDocumentTable = GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; 
runningDocumentTable.AdviseRunningDocTableEvents(this, out var dummyCookie); 

4- 不要眨眼,這裏來的魔法!執行IVsRunningDocTableEvents.OnBeforeDocumentWindowShow方法如下:

public int OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame) 
{ 
    runningDocumentTable.GetDocumentInfo(docCookie, 
     out var dummyFlags, out var dummyReadLocks, out var dummyEditLocks, 
     out string path, 
     out var dummyHierarchy, out var dummyItemId, out var dummyData); 

    IVsWindowFrame windowFrameForTextView; 
    var docIsOpenInTextView = 
     DocIsOpenInLogicalView(path, VSConstants.LOGVIEWID_Code, out windowFrameForTextView) || 
     DocIsOpenInLogicalView(path, VSConstants.LOGVIEWID_TextView, out windowFrameForTextView); 

    //Is the document open in the code/text view, 
    //AND the window for that view is the one that has been just activated? 

    ActiveDocumentIsText = docIsOpenInTextView && pFrame == logicalViewWindowFrame; 

    return VSConstants.S_OK; 
} 
相關問題