2017-10-10 288 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; 
} 
相关问题