Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VSIX: add tool window to View->Other Windows

I'm exposing a tool window in VS using this attribute on Package class:

   [ProvideToolWindow(typeof(MyToolWindow),
        Style = VsDockStyle.Tabbed,
        Orientation = ToolWindowOrientation.Right)]

This works fine and I can open it programmatically using this code:

  private void ShowToolWindow()
  {
     //this method will show the window if it's not active or bring it to front if it's collapsed
     ToolWindowPane window = this.FindToolWindow(typeof(MyToolWindow), 0, true);
     if ((null == window) || (null == window.Frame))
     {
        throw new NotSupportedException();
     }
     IVsWindowFrame windowFrame = (IVsWindowFrame)window.Frame;
     Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(windowFrame.Show());
  }

However when a user accidentally closes the window there is no way to restore it. I was wondering how other extensions add it to Tools->Other Windows, like NuGet for example. I couldn't find anything obvious in NuGet source code.

like image 967
Ivan G. Avatar asked Dec 13 '25 10:12

Ivan G.


1 Answers

You need to add a command that calls your ShowToolWindow routine.

The top of your package vsct file will need a couple external references:

<!--This is the file that defines the IDs for all the commands exposed by VisualStudio. -->
<Extern href="stdidcmd.h"/>
<!--This header contains the command ids for the menus provided by the shell. -->
<Extern href="vsshlids.h"/>

This file should define some symbols:

<Symbols>
    <!-- Use your package guid. -->
    <GuidSymbol name="guidPackage" value="{00000000-0000-0000-0000-000000000000}" />

    <!-- Use a new GUID to uniquely identify your package commands -->
    <GuidSymbol name="guidCmdSet" value="{11111111-1111-1111-1111-111111111111}">
        <IDSymbol name="cmdidViewMyToolWindow" value="0x0500" />
    </GuidSymbol>
</Symbols>

In the Buttons block of your package's vsct file, add something like:

<Button guid="guidCmdSet" id="cmdidViewMyToolWindow" priority="0x0100" type="Button">
    <!--IDG_VS_WNDO_OTRWNDWS0 is the first group in "View|Other Windows". See 
    C:\Program Files (x86)\Microsoft Visual Studio 2010 SDK SP1\VisualStudioIntegration\Common\Inc
    for other options. -->
    <Parent guid="guidSHLMainMenu" id="IDG_VS_WNDO_OTRWNDWS0"/>
    <CommandFlag>DynamicVisibility</CommandFlag>
    <CommandFlag>DefaultInvisible</CommandFlag>
    <Strings>
        <ButtonText>View &amp;My Tool Window</ButtonText>
    </Strings>
</Button>

All this should make "View My Tool Window" appear in the top section of the View menu. Now you need to take action when somebody clicks on it.

Your package should implement IOleCommandTarget to deal with command visibility and enabling:

public class MyPackage : Package, IOleCommandTarget
{
    #region IOleCommandTarget implementation

    /// <summary>
    /// The VS shell calls this function to know if a menu item should be visible and
    /// if it should be enabled/disabled.
    /// This is called only when the package is active.
    /// </summary>
    /// <param name="guidCmdGroup">Guid describing which set of commands the current command(s) belong to</param>
    /// <param name="cCmds">Number of commands for which status are being asked</param>
    /// <param name="prgCmds">Information for each command</param>
    /// <param name="pCmdText">Used to dynamically change the command text</param>
    /// <returns>HRESULT</returns>
    public int QueryStatus(ref Guid guidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
    {
        // Filter out commands that are not defined by this package
        if ( guidCmdGroup != new Guid("{00000000-0000-0000-0000-000000000000}"))
            return (int)(Constants.OLECMDERR_E_NOTSUPPORTED);

        if ( cCmds == 0 || prgCmds == null || prgCmds.Length == 0 || cCmds != prgCmds.Length )
            return VSConstants.E_INVALIDARG;

        // Show and enable all commands.
        OLECMDF cmdf = OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED;
        for ( int i = 0; i < cCmds; i++ )
            prgCmds[i].cmdf = (uint)cmdf;

        return VSConstants.S_OK;
    }

    #endregion
}

And finally, in your package initialize routine, you tell the shell what to do when your command is clicked:

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

    // Add our command handlers (commands must exist in the .vsct file)
    OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
    if ( null != mcs )
    {
        // "View My Tool Window" command callback
        CommandID menuCommandID = new CommandID(new Guid("{11111111-1111-1111-1111-111111111111}"), (int)0x500);
        MenuCommand menuItem = new MenuCommand(ShowToolWindow, menuCommandID);
        mcs.AddCommand(menuItem);
    }
}

In "real" code, you'll probably want to define some GUID constants in C# that match the symbols defined in the vsct, and use those throughout.

like image 172
Ian Olsen Avatar answered Dec 16 '25 14:12

Ian Olsen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!