2017-10-10 52 views
1

Je développe une extension Visual Studio dans laquelle l'une des commandes implémentées doit être disponible uniquement lorsque le document actif est un document texte (comme par exemple le "Toggle Bookmark" de Visual Studio). Le problème est que je ne peux pas comprendre comment dire quand c'est le cas.Comment savoir si le document actif est un document texte?

Maintenant, j'ai une solution de travail à moitié. Dans la méthode de package Initialize Je souscris à l'événement WindowActivated DTE, et chaque fois qu'une fenêtre est activée je vérifie si la fenêtre DocumentData propriété est de type 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; 
} 

Le problème avec cette approche est que 1) Window.DocumentData is documented as ".NET Framework internal use only" et 2) cela donne un faux positif quand un document qui a à la fois une vue de code et une vue de conception (par exemple un fichier .visxmanifest) est ouvert en mode conception.

J'ai essayé d'utiliser IVsTextManager.GetActiveView aussi bien, mais cela revient la dernière vue texte actif ouvert - donc si j'ouvrir un fichier .txt, puis un fichier .png, il renvoie les données pour le fichier txt même si ce n'est plus le document actif.

Alors, comment vérifier si le document actif est un document texte, ou la vue de code d'un document qui peut avoir un concepteur ... et si possible, ne pas utiliser des classes/membres "non documentés"?

MISE À JOUR: J'ai trouvé une solution légèrement meilleure. Dans la fenêtre gestionnaire activée:

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

Au moins this one is properly documented, mais je dois encore le problème des faux positifs avec les concepteurs.

Répondre

0

J'ai finalement compris. C'est un peu difficile, mais ça marche et c'est 100% "légal". Voici la recette:

1- Rendre la classe de package implémentée IVsRunningDocTableEvents. Faire toutes les méthodes que return VSConstants.S_OK;

2- Ajouter le champ suivant et la méthode auxiliaire suivant à la classe de package:

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- Ajouter le suivant à la méthode Initialize de la classe package:

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

4- Ne clignote pas, voici la magie! Implémentez la méthode IVsRunningDocTableEvents.OnBeforeDocumentWindowShow comme suit:

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; 
}