Pretty QuickInfo Tooltips and VS Themes

A Visual Studio Extension can extend quick info tooltips by implementing the IQuickInfoSource interface (and a few other things).

Most of the samples implement the AugmentQuickInfoSession() method by adding string values into the quickInfoContent collection. However, you can also add UIElement objects when you want to present tooltips that have complex content.

I implemented this for Viasfora as part of the XmlQuickInfoSource class, in order to present a much nicer tooltip for XML namespace prefixes. The end result was this:

Tooltip on Light Theme

Tooltip on Light Theme

It looked great. That is, until I tried it on Visual Studio 2012/2013 using the Dark Theme, which turned out to be unreadable:

Tooltip on Dark Theme

Tooltip on Dark Theme

After a lot of researching, I ran into the answer: There is an EnvironmentColors class included in the Microsoft.VisualStudio.Shell.(11|12).0.dll assembly, which will contains styles you can use to theme your WPF elements to properly match the selected theme.

For my needs, I could just use the ToolTipBrushKey, ToolTipTextBrushKey and PanelHyperlinkBrushKey properties to style my controls. However, I ran into a snag: The EnvironmentColors class is not available on the Visual Studio 2010 assemblies, which was a problem for me in order to support VS2010/2012/2013 with a single assembly.

While not a very pretty solution, I resorted to using Reflection coupled with the major Visual Studio version number in order to support this feature. The relevant pieces of code are:

private UIElement CreateInfoText(String xmlns, String url) {
  var textBlock = new TextBlock();
  Hyperlink hl = new Hyperlink(new Run(url));
  textBlock.Inlines.AddRange(new Inline[] {
    new Bold(new Run("Prefix: ")),
    new Run(xmlns),
    new LineBreak(),
    new Bold(new Run("Namespace: ")),
    hl
  });
  // set styles in order to support other 
  // visual studio themes on 2012/2013
  object tooltipBrushKey = VsfPackage.Instance.FindColorResource("ToolTipBrushKey");
  if ( tooltipBrushKey != null  ) {
    textBlock.SetResourceReference(TextBlock.BackgroundProperty, tooltipBrushKey);
  }
  object tooltipTextBrushKey = VsfPackage.Instance.FindColorResource("ToolTipTextBrushKey");
  if ( tooltipTextBrushKey != null ) {
    textBlock.SetResourceReference(TextBlock.ForegroundProperty, tooltipTextBrushKey);
  }
  object hlBrushKey = VsfPackage.Instance.FindColorResource("PanelHyperlinkBrushKey");
  if ( hlBrushKey != null ) {
    hl.SetResourceReference(Hyperlink.ForegroundProperty, hlBrushKey);
  }
  return textBlock;
}
private Version vsVersion;

public object FindColorResource(String name) {
  if ( vsVersion.Major <= 10 ) {
    return null;
  }
  Assembly assembly = Assembly.Load(String.Format(
    "Microsoft.VisualStudio.Shell.{0}.0, Version={0}.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
    vsVersion.Major
    ));
  if ( assembly != null ) {
    Type type = assembly.GetType("Microsoft.VisualStudio.PlatformUI.EnvironmentColors");
    var prop = type.GetProperty(name);
    return prop.GetValue(null, null);
  }
  return null;
}

Hope someone else finds this useful. Enjoy!

1 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>