Logo
HOWTO: Create a toolwindow without a ToolWindowPane class in a Visual Studio package

Author: Carlos J. Quintero (Microsoft MVP) Applies to: Microsoft Visual Studio 2010
Date: February 2015   Microsoft Visual Studio 2012
      Microsoft Visual Studio 2013
      Microsoft Visual Studio 2015
Introduction

The usual way to create a toolwindow in a Visual Studio package is to select the "Tool Window" checkbox in the page of the package wizard that asks you the package options (command, toolwindow and custom editor). In this case two classes are created: one is the usercontrol hosted inside the toolwindow and the other is a pane, implemented with a class that derives from ToolWindowPane. In addition, the package class must be decorated with the ProvideToolWindow attribute passing it the type if the ToolWindowPane-derived class (see the article HOWTO: Create a toolwindow with a ToolWindowPane class in a Visual Studio package). This approach has the advantage that Visual Studio can show when started toolwindows that were open in the last session, and it can do it even if the package is not marked to load on Visual Studio startup (if the toolwindow must be shown, Visual Studio loads the package).

Alternatively, you may want to use an approach that was used by add-ins that required only the usercontrol class, no additional classes. In add-ins this was done calling the EnvDTE80.Windows2.CreateToolWindow2() method, as explained in the article HOWTO: Create a dockable toolwindow from a Visual Studio .NET add-in. That method required the assembly/class of the usercontrol, the caption, the Guid that identified uniquely the toolwindow and an AddIn instance. Due to this parameter it cannot be used by packages, but the IVsUIShell interface provides a CreateToolWindow method that can be used from packages. Visual Studio remembers the size, position, docking, etc. of toolwindows created with this approach too (it uses the Guid that identifies the toolwindow to store that information). The only drawback of this approach is that Visual Studio won't show the toolwindow if it was opened in the last session. However, when your package is loaded, the package can do it itself just using a custom registry setting to store if the toolwindow was open when the package is unloaded.

More Information

The following package creates a toolwindow without using a class that inherits from ToolWindowPane:

Language: C#   Copy Code Copy Code (IE only)
using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.ComponentModel.Design;
using Microsoft.Win32;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;

namespace MyCompany.VSPackageToolWindow
{
   [PackageRegistration(UseManagedResourcesOnly = true)]
   [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
   [ProvideMenuResource("Menus.ctmenu", 1)]
   [Guid(GuidList.guidVSPackageToolWindowPkgString)]
   public sealed class VSPackageToolWindowPackage : Package
   {
      private IVsWindowFrame m_windowFrame = null;
      private UserControl1 m_userControl;

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

         // Add our command handlers for menu (commands must exist in the .vsct file)
         OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
         if (null != mcs)
         {
            // Create the command for the menu item.
            CommandID menuCommandID = new CommandID(GuidList.guidVSPackageToolWindowCmdSet, (int)PkgCmdIDList.cmdidMyToolWindow);
            MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
            mcs.AddCommand(menuItem);
         }
      }

      private void MenuItemCallback(object sender, EventArgs e)
      {
         ShowToolWindow();
      }

      private void ShowToolWindow()
      {
         // TODO: Change this Guid
         const string TOOLWINDOW_GUID = "{put-your-toolwindow-guid-here}";

         if (m_windowFrame == null)
         {
            m_userControl = new UserControl1();
            m_windowFrame = CreateToolWindow("My toolwindow", TOOLWINDOW_GUID, m_userControl);

            // TODO: Initialize m_userControl if required adding a method like:
            //    internal void Initialize(VSPackageToolWindowPackage package)
            // and pass this instance of the package:
            //    m_userControl.Initialize(this);
         }
         m_windowFrame.Show();
      }

      private IVsWindowFrame CreateToolWindow(string caption, string guid, System.Windows.Forms.UserControl userControl)
      {
         const int TOOL_WINDOW_INSTANCE_ID = 0; // Single-instance toolwindow

         IVsUIShell uiShell;
         Guid toolWindowPersistenceGuid;
         Guid guidNull = Guid.Empty;
         int[] position = new int[1];
         int result;
         IVsWindowFrame windowFrame = null;

         uiShell = (IVsUIShell)GetService(typeof(SVsUIShell));

         toolWindowPersistenceGuid = new Guid(guid);

         result = uiShell.CreateToolWindow((uint)__VSCREATETOOLWIN.CTW_fInitNew,
               TOOL_WINDOW_INSTANCE_ID, userControl, ref guidNull, ref toolWindowPersistenceGuid,
               ref guidNull, null, caption, position, out windowFrame);

         Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(result);

         return windowFrame;
      }
   }
}

Related articles



Go to the 'Visual Studio Extensibility (VSX)' web site for more articles like this (Articles section)