Visual Studio Extensions: How to get colors from the VS theme

TL;DR:

// Note that I've only tried this in VS 2022.
// Browse the EnvironmentColors class to see all the available colors.
var themeColor = VSColorTheme.GetThemedColor(EnvironmentColors.ToolWindowBackgroundColorKey);
// If you want to use this in a WPF brush, convert it like this.
var wpfCompatibleColor = Color.FromRgb(themeColor.R, themeColor.G, themeColor.B);

Read on for full details.

If you’re writing a Visual Studio extension and you have a tool window, you’ll likely want to have that window match the visual theme of the Visual Studio instance into which it’s installed. Unless you’re a psychopath.

If you’re not a psychopath*, consider the following example.

Let’s say you have a tool window containing a TextBox which fills the entire tool window, like in my open source scratchpad extension, Scratchy. Here’s what that looks like in the XAML designer:

Visual Studio XAML window showing an extension tool window.

When the window loads, I want it to check the current Visual Studio theme and get the appropriate background and foreground colors (foreground for the text color). In the code of the tool window (ScratchyToolWindowControl in my case), let’s create a private method to retrieve the color from the `VSColorTheme` class and convert it into a format we can use in a WPF brush:

// Add these usings.
using System.Windows.Media;
using Microsoft.VisualStudio.PlatformUI;
using Microsoft.VisualStudio.Shell;

/// <summary>
/// Get a color from the current Visual Studio theme in a format appropriate
/// for WPF brushes.
/// </summary>
/// <param name="colorKey">A value from the <see cref="EnvironmentColors" /> class.</param>

private static Color GetColorFromVsTheme(ThemeResourceKey colorKey)
{
    var themeColor = VSColorTheme.GetThemedColor(colorKey);
    // Convert to a System.Windows.Media.Color, which can be used in WPF brushes.
    return Color.FromRgb(themeColor.R, themeColor.G, themeColor.B);
}

We can then call this to set the background and foreground colors of the TextBox. Let’s create another private method to do that (we’ll use this again shortly):

private void SetToolWindowTheme()
{
    ScratchPadTextBox.Background = new SolidColorBrush(GetColorFromVsTheme(EnvironmentColors.ToolWindowBackgroundColorKey));
    ScratchPadTextBox.Foreground = new SolidColorBrush(GetColorFromVsTheme(EnvironmentColors.ToolWindowTextColorKey));
}

Now you can just call SetToolWindowTheme() from the tool window’s contructor to set the colors when the window loads. Here’s how it looks at runtime with the Dark VS theme:

Scratch tool window docked into an experimental Visual Studio instance.

What happens if the user changes their theme without reloading Visual Studio? As it stands, your window won’t respond to that change. Fortunately, Microsoft provides a handy event to which we can subscribe so that we get notified when that happens. Create one more simple private method which we’ll use to handle the event:

private void HandleThemeChange(ThemeChangedEventArgs e)
{
    SetToolWindowTheme();
}

Now just add one more line to your constructor to subscribe to the event:

VSColorTheme.ThemeChanged += HandleThemeChange;

That’s it! With this technique you can easily adapt your extension’s UI to match Visual Studio’s theme. See the full sample code with all the above methods in the Scratchy project here.

*psychopaths also very much welcome

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.