Monday, January 1, 2018

VSIX Winforms Toolpane

The other day I wanted to create a Visual Studio Toolpane window and I wanted to create it using Winforms (by default, the toolpanes use WPF).

After much research, I got it to work. These are the steps I followed:

I've tested these steps with Visual Studio 2015 & Visual Studio 2017.

  1. Create a new Extensibility project
    1. In Visual Studio, from the File menu, select New --> Project.
    2. In the New Project dialog, one the left, under Visual C#, select Extensibility.
    3. On the right, select VSIX Project.
    4. Give the project a name. In this example, I'm calling it MySampleVSIXProject
  2. Add a Visual Studio Package
    1. Right-click the project in Solution Explorer and select Add --> New Item
    2. In the Add New Item dialog, on the left, expand Extensibility and select VSPackage.
    3. On the right, select Custom Tool Window.
    4. Give the tool window a name. In this example, I'm calling it MySampleToolWindow.cs
  3. Add a Winforms User Control
    1. Right-click the project in Solution Explorer and select Add --> New Item
    2. In the Add New Item dialog, on the left, select Windows Forms
    3. On the right select User Control
    4. Give the User Control a name. In this example, I'm calling it MySampleUserControl.cs
    5. Drag a label to the control so we can see something when we run it. Change the Text property. In this example, I changed it to "I'm a Winforms Control".
  4. Substitute our Winform Control for the WPF Control
    1. Open the MySampleToolWindow.cs file. It should look something like this (I've removed the comments for simplicity):
    2. 
        public class MySampleToolWindow : ToolWindowPane
        {
         public MySampleToolWindow() : base(null)
         {
          this.Caption = "MySampleToolWindow";
          this.Content = new MySampleToolWindowControl();
         }
        }
      
       
    3. Add a field to the MySampleToolWindow class. Make it of type MySampleUserControl and name it control.
    4. Then comment out the line that says "this.Content = new MySampleToolWindowControl();"
    5. Under the commented out line, add a line to create an instance of our control.
    6.   public class MySampleToolWindow : ToolWindowPane
        {
         public MySampleUserControl control; 
         public MySampleToolWindow() : base(null)
              {
                  this.Caption = "MySampleToolWindow";
                  //this.Content = new MySampleToolWindowControl();
                  this.control = new MySampleUserControl();
              } 
        }
       
    7. Add a using System.Windows.Forms; statement at the top of the code.
    8. Next, add this code to the class:
    9.         public override IWin32Window Window
              {
                  get
                  {
                      return (IWin32Window)control;
                  }
              }
       
      It should now look like this:
          public class MySampleToolWindow : ToolWindowPane
          {
              public MySampleUserControl control; 
              public MySampleToolWindow() : base(null)
              {
                  this.Caption = "MySampleToolWindow";
                  //this.Content = new MySampleToolWindowControl();
                  this.control = new MySampleUserControl();
              }
      
              public override IWin32Window Window
              {
                  get
                  {
                      return (IWin32Window)control;
                  }
              }
          }
       

Now we can run the project. In the experimental version of Visual Studio that opens, from the View menu, under Other Windows, you should see our window ("MySampleToolWindow".) Click it to open our window. It opens in a window by itself.

That's great. But what if we want it to open already docked to the Solution Explorer panel?

That's easy. We just have to add some attributes. Open the MySampleToolWindowPackage.cs. On the MySampleToolWindowPackage class, find the ProvideToolWindow attribute. It should look like this:

[ProvideToolWindow(typeof(MySampleToolWindow))]
 

We'll add these Style and Windows attributes to it:

[ProvideToolWindow(typeof(MySampleToolWindow),  
    Style = Microsoft.VisualStudio.Shell.VsDockStyle.Tabbed,  
    Window = "3ae79031-e1bc-11d0-8f78-00a0c9110057"))]
 
According to this MSDN page:
"The first named parameter is Style and its value is Tabbed, which means that the window will be a tab in an existing window. The docking position is specified by the Window parameter, in this case, the GUID of the Solution Explorer."

Now if we run it, it will show up next to the Solution Explorer:

At this point, you can optionally delete the MySampleToolWindowControl.xaml file. This is the WPF control that we're not using.

No comments: