Skip to content

Aldaviva/BensButtons

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 

🛠 Ben's Buttons

Visual Studio Marketplace

Add custom buttons to the Visual Studio toolbar.

External Tools are easy to create, but they don't let you specify custom icons for some reason.

Requirements

Buttons

Custom buttons in VS toolbar

  • Bitbucket
    • Browse current repository's Bitbucket web page
  • Git Extensions
  • GitHub
    • Browse current repository's GitHub web page
  • Sublime Text
  • Total Commander

Installation

Usage

  • Buttons are available in the Tools › Ben's Buttons submenu
  • Add a button to a toolbar
    1. On the toolbar, click … › Add or Remove Buttons › Customize…
    2. Click Add Command…
    3. Select the Tools category
    4. Select one of the buttons provided by this extension, then click OK
    5. Arrange the new button using Move Up, Move Down, and Modify Selection to make it appear as desired
  • Add a keyboard shortcut to a button
    1. Go to Tools › Options › More Settings (VS ≥ 2026) › Keyboard
    2. Search for the command with the Tools.BensButtons. prefix, such as Tools.BensButtons.GitExtensions
    3. Type the desired key combination in the Press shortcut keys text box
    4. Click Assign

Developing buttons

Do you want to integrate with a different program, or change which pane Total Commander opens your project directory in? To add new buttons beyond what this extension already provides, or edit the built-in buttons, you can fork this repository and edit its source.

In general, just search this project for all 5 other instances of Add new buttons here and make a new one that looks like the existing buttons. It's easier than the piles of XML make it seem.

  1. Add new button to menus.vsct.
    • New buttons go in /CommandTable/Commands/Buttons
    • Add a new button definition that looks like
      <Button guid="commandSet" id="myProgram" priority="106" type="Button">
          <Parent guid="commandSet" id="submenuGroup" />
          <Icon guid="imageManifest" id="myProgram" />
          <CommandFlag>IconIsMoniker</CommandFlag>
          <Strings>
              <ButtonText>My Program</ButtonText>
              <ToolTipText>Open file in My Program</ToolTipText>
              <CanonicalName>BensButtons.MyProgram</CanonicalName>
              <LocCanonicalName>BensButtons.MyProgram</LocCanonicalName>
          </Strings>
      </Button>
    • Replace the myProgram command ID symbol with your own arbitrary command ID symbol
    • Replace ButtonText, ToolTipText, CanonicalName, and LocCanonicalName with the friendly name of the program, a description of the button action, and two versions without spaces, respectively
    • Replace priority with the sort index of this button, which should be unique among buttons in the submenuGroup command group
    • Add two new command IDs to the /CommandTable/Symbols/GuidSymbol elements
      • The commandSet should contain a command ID like
        <IDSymbol name="myProgram" value="106" />
        where the name was used above in the Button/@id, and the value is not used by any other commands and is therefore unique in the command set
      • The imageManifest should contain the icon ID like
        <IDSymbol name="myProgram" value="106" />
        where the name was used above in the Button/Icon/@id, and the value is unique in the image manifest; it doesn't have to be the same as the value from the commandSet
  2. Import images into the project.
    • Image files go in the Resources directory
    • Accepted formats are PNG (raster, 32bpp including transparency) and XAML (vector)
    • Native raster dimensions are 16×16px for 100% scaling, and vector images are scaled correctly regardless of the viewbox size
    • Different formats can be mixed in the same image, for example a 16px raster image for 100% scaling, 32px for 200%, and a vector fallback for all other scaled sizes such as 48px (300%)
    • Images can have variations for light and dark mode
    • All PNG files must have their Build Action changed from Content to Resource, which should be handled automatically by the project
  3. Add new images to images.imagemanifest
    • New Image elements go in /ImageManifest/Images
    • Add a new image definition that looks like
      <Image Guid="$(imageManifest)" ID="106" AllowColorInversion="false">
          <Source Uri="$(Resources)/myProgram-16.png">
              <Size Value="16" />
          </Source>
          <Source Uri="$(Resources)/myProgram-24.png">
              <Size Value="24" />
          </Source>
          <Source Uri="$(Resources)/myProgram-32.png">
              <Size Value="32" />
          </Source>
          <Source Uri="$(Resources)/myProgram-48.png">
              <Size Value="48" />
          </Source>
      </Image>
    • Replace the ID with the number used in menus.vsct in the value for the IDSymbol for imageManifest
    • Replace the filename with the PNG or XAML filename, prefixed with $(Resources)/ to load it from the correct library and folder
    • The size is the edge length of the image in physical pixels when this source is allowed to be used (16px at 100% scaling, 24px at 150%, etc)
    • To specify different images for light and dark mode, set the Background attribute on the Source to Light or Dark, respectively; otherwise you can set Image/@AllowColorInversion to false to prevent Visual Studio from inverting the black and white pixels of the image in dark mode
      <Image Guid="$(imageManifest)" ID="106">
          <Source Uri="$(Resources)/myprogram-light.xaml" Background="Light" />
          <Source Uri="$(Resources)/myprogram-dark.xaml" Background="Dark" />
      </Image>
    • Vector images can be converted using SvgToXaml, although the XAML it generates needs to be reorganized to work in a standalone XAML file: the DrawingGroup must be removed from the DrawingImage and put in a DrawingBrush's Drawing property, which goes inside a Rectangle inside a Viewbox; see github-dark.xaml and bitbucket.xaml for examples
      <Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
          <Rectangle Width="16" Height="16">
              <Rectangle.Fill>
                  <DrawingBrush>
                      <DrawingBrush.Drawing>
                          <!-- DrawingGroup element and descendants from SvgToXaml -->
                      </DrawingBrush.Drawing>
                  </DrawingBrush>
              </Rectangle.Fill>
          </Rectangle>
      </Viewbox>
  4. Add a new button command class.
    • Subclass AbstractButtonCommand
      namespace BensButtons.Commands;
      
      internal class MyProgram: AbstractButtonCommand {
      
          public override int commandId => 106;
      
          protected override async Task onClick() {
              // TODO: button was clicked
          }
      }
    • Replace the commandId property value with the value of your new IDSymbol for commandSet in menus.vsct
    • Handle the button click event in the onClick method
  5. Register the new button class in the MyPackage class
    • Add a new constructor call to your button class in the registerButtons method, and call register on the new instance
      new MyProgram { extensionPackage = this, visualStudio = visualStudio }.register(commandService);
  6. Test your changes in another instance of Visual Studio
    1. Clean and Rebuild your extension (not just Build) to make sure code and image changes aren't ignored by the VSPackage compiler's faulty incremental build logic
    2. Click Start without Debugging to install the extension into a separate Visual Studio instance and launch it
    3. Look in the Tools › Ben's Buttons menu
  7. On build, this extension will be compiled into bin\$(Configuration)\BensButtons.vsix, which you can double-click to install in Visual Studio