2011-08-25 4 views
7

Tengo un resaltador de sintaxis administrado utilizando la nueva API de extensibilidad VS y me da un ITextBuffer, que es genial.¿Cómo puedo obtener un ITextBuffer fuera de EnvDTE.Window?

En otra parte de mi extensión obtengo un objeto DTE y me adjunto al evento de cambio de ventana activa, lo que me da un objeto EnvDTE.Window.

var dte = (EnvDTE.DTE)this.GetService(typeof(EnvDTE.DTE)); 
dte.Events.WindowEvents.WindowActivated += WindowEvents_WindowActivated; 
// ... 

private void WindowEvents_WindowActivated(EnvDTE.Window GotFocus, EnvDTE.Window LostFocus) 
{ 
    // ??? 
    // Profit 
} 

Me gustaría obtener el ITextBuffer fuera de la ventana en este método. ¿Alguien puede decirme una manera directa de hacer eso?

Respuesta

9

La solución que utilicé fue obtener la ruta de Windows y luego usarla junto con IVsEditorAdaptersFactoryService y VsShellUtilities.

var openWindowPath = Path.Combine(window.Document.Path, window.Document.Name); 
var buffer = GetBufferAt(openWindowPath); 

y

internal ITextBuffer GetBufferAt(string filePath) 
{ 
    var componentModel = (IComponentModel)GetService(typeof(SComponentModel)); 
    var editorAdapterFactoryService = componentModel.GetService<IVsEditorAdaptersFactoryService>(); 
    var serviceProvider = new Microsoft.VisualStudio.Shell.ServiceProvider(MetaSharpPackage.OleServiceProvider); 

    IVsUIHierarchy uiHierarchy; 
    uint itemID; 
    IVsWindowFrame windowFrame; 
    if (VsShellUtilities.IsDocumentOpen(
    serviceProvider, 
    filePath, 
    Guid.Empty, 
    out uiHierarchy, 
    out itemID, 
    out windowFrame)) 
    { 
    IVsTextView view = VsShellUtilities.GetTextView(windowFrame); 
    IVsTextLines lines; 
    if (view.GetBuffer(out lines) == 0) 
    { 
     var buffer = lines as IVsTextBuffer; 
     if (buffer != null) 
     return editorAdapterFactoryService.GetDataBuffer(buffer); 
    } 
    } 

    return null; 
} 
+0

+1, pero tenga en cuenta que 'IsDocumentOpen()' devuelve a veces falsa cuando el documento está aún en proceso de ser abierto (VS llama a código de usuario para hacer, por ejemplo, , análisis de archivos antes de que actualice su lista interna de ventanas abiertas). La única solución que he encontrado para eso es enumerar todos los marcos de ventana, obtener VSFPROPID_ExtWindowObject para cada uno y compararlo con EnvDTE.Window (cuyo FullName del documento coincide con la ruta deseada). – Cameron

+1

Además, las ventanas incrustadas del documento Peek no tienen un 'IVsWindowFrame' por lo que puedo decir, por lo que' IsDocumentOpen' fallará aunque el documento esté "abierto" en la tabla de documentos en ejecución. Todavía puede obtener el búfer utilizando el método 'FindAndLockDocument' de' IVsRunningDocumentTable' directamente (que es lo que 'IsDocumentOpen' está llamando internamente). Obviamente, si tiene un objeto 'EnvDTE.Window' en primer lugar, esto no se aplica, pero si solo tiene la ruta, es importante saber sobre este caso de esquina. – Cameron

Cuestiones relacionadas