Logo
HOWTO: Get the current theme and detect changing it from a Visual Studio 2012 add-in.

Author: Carlos J. Quintero (Microsoft MVP) Applies to: Microsoft Visual Studio 2012
Date: September 2012    
       
Introduction

Visual Studio 2012 can show its user interface with two themes, Dark and Light, that can be selected in the "Tools", "Options..." menu, "Environment", "General" section. Visual Studio extensions should adapt its user interface to the current theme. This article explains how to know the current theme and how to be notified when it is changed.

More information

Visual Studio 2012 stores the currently selected theme in the following registry location:

Registry key: HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0\General

Name: CurrentTheme

Values:

  • Light theme: "de3dbbcd-f642-433c-8353-8f1df4370aba"
  • Dark theme: "1ded0138-47ce-435e-84ef-9ec1f439b749"

One thing to notice is that when you have several Visual Studio 2012 instances and you change the theme in one of them, it is changed in all of them. Visual Studio 2012 does this by sending a WM_SYSCOLORCHANGE message, which is sent to all top-level windows.

So, while an add-in could detect when the user has changed the current theme intercepting the AfterExecute event of the CommandEvents class for the "Tools.Options" command checking if the theme has changed (as explained in the article HOWTO: Capturing commands events from Visual Studio .NET add-in), it is much better to intercept the WM_SYSCOLORCHANGE message.

The following sample shows the code of an add-in that shows the current theme when loaded and every time the theme is changed. The add-in intercepts the WM_SYSCOLORCHANGE message using a dummy invisible top-level Form1 and trapping its SystemColorsChanged event. The Form is shown invisibly by doing the following:

  • In the Load event, sets its Size to (0,0).
  • Before showing it, set its properties ShowInTaskbar to false and FormBorderStyle to FormBorderStyle.None.
Language: VB.NET   Copy Code Copy Code (IE only)
Public Class Form1

   Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

      Me.Size = New System.Drawing.Size(0, 0)

   End Sub

End Class

---------------------------------------------------------------------------------------------------------

Imports System
Imports Extensibility
Imports EnvDTE
Imports EnvDTE80

Public Class Connect	
   Implements IDTExtensibility2

   Private _applicationObject As DTE2
   Private _addInInstance As AddIn
   Private _themeId As String
   Private WithEvents _frm1 As Form1

   Public Sub OnConnection(ByVal application As Object, ByVal connectMode As ext_ConnectMode, _
      ByVal addInInst As Object, ByRef custom As Array) Implements IDTExtensibility2.OnConnection

      _applicationObject = CType(application, DTE2)
      _addInInstance = CType(addInInst, AddIn)

      Select Case connectMode

         Case ext_ConnectMode.ext_cm_Startup
            ' OnStartupComplete will be called

         Case ext_ConnectMode.ext_cm_AfterStartup
            InitializeAddIn()

      End Select

   End Sub

   Public Sub OnDisconnection(ByVal disconnectMode As ext_DisconnectMode, ByRef custom As Array) _
      Implements IDTExtensibility2.OnDisconnection

      If _frm1 IsNot Nothing Then
         _frm1.Close()
         _frm1 = Nothing
      End If

   End Sub

   Public Sub OnAddInsUpdate(ByRef custom As Array) Implements IDTExtensibility2.OnAddInsUpdate
   End Sub

   Public Sub OnStartupComplete(ByRef custom As Array) Implements IDTExtensibility2.OnStartupComplete

      InitializeAddIn()

   End Sub

   Public Sub OnBeginShutdown(ByRef custom As Array) Implements IDTExtensibility2.OnBeginShutdown
   End Sub

   Private Sub InitializeAddIn()

      _themeId = GetThemeId()

      ShowTheme()

      _frm1 = New Form1()
      _frm1.ShowInTaskbar = False
      _frm1.FormBorderStyle = FormBorderStyle.None

      _frm1.Show()

   End Sub

   Private Function GetThemeId() As String

      Const CATEGORY_TEXT_GENERAL As String = "General"
      Const PROPERTY_NAME_CURRENT_THEME As String = "CurrentTheme"

      Dim result As String

      result = Microsoft.Win32.Registry.GetValue("HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0\" & _
         CATEGORY_TEXT_GENERAL, PROPERTY_NAME_CURRENT_THEME, "").ToString()

      Return result

   End Function

   Private Sub _frm1_SystemColorsChanged(sender As Object, e As EventArgs) Handles _frm1.SystemColorsChanged

      Dim newThemeId As String

      newThemeId = GetThemeId()

      If newThemeId <> _themeId Then

         _themeId = newThemeId

         ShowTheme()

      End If

   End Sub

   Private Sub ShowTheme()

      Const THEME_LIGHT As String = "de3dbbcd-f642-433c-8353-8f1df4370aba"
      Const THEME_DARK As String = "1ded0138-47ce-435e-84ef-9ec1f439b749"

      Select Case _themeId

         Case THEME_DARK

            MessageBox.Show("Current theme is Dark")

         Case THEME_LIGHT

            MessageBox.Show("Current theme is Light")

      End Select

   End Sub

End Class
Language: C#   Copy Code Copy Code (IE only)
using System;
using System.Drawing;
using System.Windows.Forms;

namespace MyAddIn1
{
   public partial class Form1 : Form
   {
      public Form1()
      {
         InitializeComponent();
      }

      private void Form1_Load(object sender, EventArgs e)
      {

         this.Size = new Size(0, 0);
      }
   }
}

---------------------------------------------------------------------------------------------------------

using System;
using Extensibility;
using EnvDTE;
using EnvDTE80;
using System.Windows.Forms;

namespace MyAddIn1
{

   public class Connect : IDTExtensibility2
   {
      private DTE2 _applicationObject;
      private AddIn _addInInstance;
      private string _themeId;
      private Form1 _frm1;

      public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
      {
         _applicationObject = (DTE2)application;
         _addInInstance = (AddIn)addInInst;

         switch (connectMode)
         {
            case ext_ConnectMode.ext_cm_AfterStartup:
               InitializeAddIn();
               break;
            case ext_ConnectMode.ext_cm_Startup:
               // OnStartupComplete will be called
               break;
         }
      }

      public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
      {
         if (_frm1 != null)
         {
            _frm1.SystemColorsChanged -= _frm1_SystemColorsChanged;
            _frm1.Close();
            _frm1 = null;
         }
      }

      public void OnAddInsUpdate(ref Array custom)
      {
      }

      public void OnStartupComplete(ref Array custom)
      {
         InitializeAddIn();
      }

      public void OnBeginShutdown(ref Array custom)
      {
      }

      private void InitializeAddIn()
      {
         _themeId = GetThemeId();

         ShowTheme();

         _frm1 = new Form1();
         _frm1.ShowInTaskbar = false;
         _frm1.FormBorderStyle = FormBorderStyle.None;
         _frm1.SystemColorsChanged += _frm1_SystemColorsChanged;
         _frm1.Show();

      }

      private string GetThemeId()
      {
         const string CATEGORY_TEXT_GENERAL = "General";
         const string PROPERTY_NAME_CURRENT_THEME = "CurrentTheme";

         string result;

         result = Microsoft.Win32.Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0\" 
            + CATEGORY_TEXT_GENERAL, PROPERTY_NAME_CURRENT_THEME, "").ToString();

         return result;
      }

      private void _frm1_SystemColorsChanged(object sender, System.EventArgs e)
      {
         string newThemeId;

         newThemeId = GetThemeId();

         if (newThemeId != _themeId)
         {
            _themeId = newThemeId;
            ShowTheme();
         }
      }

      private void ShowTheme()
      {
         const string THEME_LIGHT = "de3dbbcd-f642-433c-8353-8f1df4370aba";
         const string THEME_DARK = "1ded0138-47ce-435e-84ef-9ec1f439b749";

         switch (_themeId)
         {

            case THEME_DARK:

               MessageBox.Show("Current theme is Dark");
               break;

            case THEME_LIGHT:

               MessageBox.Show("Current theme is Light");
               break;

         }
      }
   }
}

Related articles



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


Top