c++visual-studioenvdte

Visual Studio DTE Extension Move Tabs


I have been trying to sort/move editor tabs in a visual studio extension. But I can't find the right methods for it. I can get the source code file names but couldn't figure out the API methods how to move the windows/tabs. Can somebody give me a hint?

DTE dte = Package.GetGlobalService(typeof(DTE)) as DTE;

            foreach (Window w in dte.Windows)
            {
                if ( w.Document != null)
                {
                    Console.WriteLine(w.Document.Name);
                    //store name/extension and sort/move tab window afterwards.
                   
                }

enter image description here


Solution

  • This is a pretty obscure area and few would likely know how to do it at the top of their head. Based on my knowledge of VS extensions however (I'm the author of a commercial extension), I attempted to quickly cobble together something for you. I was able to get as far as determining the open tabs (actually window "frames", you can get the collection and sort them), but then I hit a roadblock because apparently (from what I could quickly gather anyway - more research required), there's no MSFT (API) method to actually reorder them. They apparently have to be closed first and then re-opened in the new order you want though I'm not certain of that without further research (but it appears that way from the limited research I did). If it is in fact the case then it can seriously disrupt the user-experience of course (closing and opening files just to reorder tabs) and what do you do if a given file needs to be saved first? Not good so I gave up at this point.

    Here's the code I was working on if you wish to pursue it. It's in rough shape still though (just quickly hacked it together), but enough to get you started. "GetWindowFrames()" returns the open frames (tabs) but now you would have to close and reopen them in the order you want because there's no API that does it as I said. I'll leave it to you to investigate further though (to make sure). Even if there is a way however, you may want to do additional research to see if the following approach is how Microsoft would even recommend doing it. Maybe there's a better way but again, it was just my first crack at it.

    using System;
    using System.Collections.Generic
    using EnvDTE;
    using Microsoft.VisualStudio;
    using Microsoft.VisualStudio.Shell;
    using Microsoft.VisualStudio.Shell.Interop
    
    namespace VisualStudioSDK
    {
        static public class DTEExtensionMethods
        {
            public static TService GetService<TService>(this DTE dte,
                                                        Type serviceType,
                                                        bool throwIfNotFound) where TService : class
            {   
                Microsoft.VisualStudio.OLE.Interop.IServiceProvider serviceProvider = (Microsoft.VisualStudio.OLE.Interop.IServiceProvider)dte;
    
                return serviceProvider.GetService<TService>(serviceType, throwIfNotFound);
            }
        }
        
        static public class ServiceProviderExtensionMethods
        {
            public static TService GetService<TService>(this Microsoft.VisualStudio.OLE.Interop.IServiceProvider serviceProvider,
                                                        Type serviceType,
                                                        bool throwIfNotFound) where TService : class
            {   
                TService service = serviceProvider.GetService(serviceType) as TService;
                if (service == null && throwIfNotFound)
                {
                   // Throw here
                }
    
                return service;
            }
            
            private static object GetService(this Microsoft.VisualStudio.OLE.Interop.IServiceProvider serviceProvider,
                                             Type serviceType)
            {
                object service;
    
                using (ServiceProvider sp = new ServiceProvider(serviceProvider))
                {
                    service = sp.GetService(serviceType);
                }
    
                return service;
            }
        }
    }
    
    List<IVsWindowFrame> GetWindowFrames(IVsUIShell uiShell)
    {
        List<IVsWindowFrame> frames = new List<IVsWindowFrame>();
        IEnumWindowFrames enumWindowFrames;
        uiShell.GetDocumentWindowEnum(out enumWindowFrames);
    
        IVsWindowFrame[] frameArray = new IVsWindowFrame[1];
        uint fetched;
        while (enumWindowFrames.Next(1, frameArray, out fetched) == VSConstants.S_OK && fetched == 1)
        {
            frames.Add(frameArray[0]);
        }
        return frames;
    }
    
    IVsUIShell uiShell = dte.GetService<IVsUIShell>(typeof(SVsUIShell),
                                                    throwIfNotFound:true);
    List<IVsWindowFrame> windowFrames = GetWindowFrames(uiShell);