如何获取Visual Studio当前使用的颜色主题

时间:2013-04-10 08:22:10

标签: visual-studio-2012 intellisense visual-studio-extensions

我正在创建自己的IntelliSense Presenter,因为Visual Studio2012支持更改主题,因此我希望在更改主题时可以自动更改演示者的背景颜色。有没有办法跟踪主题更改事件,或获取Visual Studio的当前颜色主题?

3 个答案:

答案 0 :(得分:13)

是的,这是可能的。我不得不用我的一个扩展解决一个类似的问题...... 当前主题存储在Windows注册表中;所以我实现了以下实用程序类。

public enum VsTheme
{
    Unknown = 0, 
    Light, 
    Dark, 
    Blue
}

public class ThemeUtil
{
    private static readonly IDictionary<string, VsTheme> Themes = new Dictionary<string, VsTheme>()
    {
        { "de3dbbcd-f642-433c-8353-8f1df4370aba", VsTheme.Light }, 
        { "1ded0138-47ce-435e-84ef-9ec1f439b749", VsTheme.Dark }, 
        { "a4d6a176-b948-4b29-8c66-53c97a1ed7d0", VsTheme.Blue }
    };

    public static VsTheme GetCurrentTheme()
    {
        string themeId = GetThemeId();
        if (string.IsNullOrWhiteSpace(themeId) == false)
        {
            VsTheme theme;
            if (Themes.TryGetValue(themeId, out theme))
            {
                return theme;
            }
        }

        return VsTheme.Unknown;
    }

    public static string GetThemeId()
    {
        const string CategoryName = "General";
        const string ThemePropertyName = "CurrentTheme";
        string keyName = string.Format(@"Software\Microsoft\VisualStudio\11.0\{0}", CategoryName);

        using (RegistryKey key = Registry.CurrentUser.OpenSubKey(keyName))
        {
            if (key != null)
            {
                return (string)key.GetValue(ThemePropertyName, string.Empty);
            }
        }

        return null;
    }
}

好;这只是帮助确定当前的设置...听主题改变通知有点棘手。加载包后,必须通过DTE获取IVsShell实例;一旦有了这个对象,就可以利用AdviceBroadcastMessages方法订阅事件通知。您必须提供一个类型实现IVsBroadcastMessageEvents接口的对象...

我不想发布整个实现,但以下几行可能会说明关键场景......

class VsBroadcastMessageEvents : IVsBroadcastMessageEvent
{
    int IVsBroadcastMessageEvent.OnBroadcastMessage(uint msg, IntPtr wParam, IntPtr lParam)
    {
        const uint WM_SYSCOLORCHANGE = 0x15;
        if (msg == WM_SYSCOLORCHANGE) 
        {
            // obtain current theme from the Registry and update any UI...
        }
    }
}

考虑在该类型上实现IDisposable,以便在卸载软件包时能够取消订阅事件源。

这是我订阅活动通知的方式......

class ShellService
{
    private readonly IVsShell shell;
    private bool advised;

    public ShellService(IVsShell shellInstance)
    {
        this.shell = shellInstance;
    }

    public void AdviseBroadcastMessages(IVsBroadcastMessageEvents broadcastMessageEvents, out uint cookie)
    {
        cookie = 0;
        try
        {
            int r = this.shell.AdviseBroadcastMessages(broadcastMessageEvents, out cookie);
            this.advised = (r == VSConstants.S_OK);
        }
        catch (COMException) { }
        catch (InvalidComObjectException) { }
    }

    public void UnadviseBroadcastMessages(uint cookie)
    {
        ...
    }
}

保留cookie参数的值;你需要它才能成功取消订阅。

希望有所帮助( - :

答案 1 :(得分:10)

只是想更新以防万一其他人出现.. @Matze和@Frank完全正确..但是在VS 2015中......他们添加了一种简单的方法来检测主题变化。因此,您需要包含PlatformUI,才能获得超级简单的事件

var defaultBackground = VSColorTheme.GetThemedColor(EnvironmentColors.ToolWindowBackgroundColorKey);
var defaultForeground = VSColorTheme.GetThemedColor(EnvironmentColors.ToolWindowTextColorKey);

你应该确保你的控制是一次性的,这样你就可以取消订阅活动......

奖金!

它还可以让您轻松访问颜色..即使用户已将其更改为默认值..因此您可以在设置颜色时执行此类操作

stats1 = {
  "Test1" => {
    "Variant A" => 10,
    "Variant B" => 20
  },
  "Test2" => {
    "Variant C" => 30,
    "Variant D" => 40
  }
}

stats2 = {
   "Test1" => {
     "Variant A" => 1,
     "Variant B" => 2
   },
   "Test2" => {
     "Variant C" => 3,
     "Variant D" => 4
   }
}

答案 2 :(得分:7)

对于VS 2015,这已经发生了变化,解决方案@Matze仍然有效,但您需要更新GetThemeId()函数以检查版本,如果它是14.0(VS2015),请查看注册表中的其他位置。存储值的方式也发生了变化,它仍然是一个字符串,但现在包含由'*'分隔的其他值。主题guid是列表中的最后一个值。

if (version == "14.0")
{
   string keyName = string.Format(@"Software\Microsoft\VisualStudio\{0}\ApplicationPrivateSettings\Microsoft\VisualStudio", version);

   using (RegistryKey key = Registry.CurrentUser.OpenSubKey(keyName))
   {
      if (key != null)
      {
          var keyText = (string)key.GetValue("ColorTheme", string.Empty);

              if (!string.IsNullOrEmpty(keyText))
              {
                  var keyTextValues = keyText.Split('*');
                  if (keyTextValues.Length > 2)
                  {
                       return keyTextValues[2];
                  }
              }
      }
   }

   return null;
}