Standard controls in VS 2012 extension

2020-06-16 06:22发布

问题:

I am currently changing a company-internal VS extension to support Visual Studio 2012. What I am struggling with is how to make the UI adapting to the active VS theme dynamically.

I found several resource keys for colors/brushes (VsColors/VsBrushes in Microsoft.VisualStudio.Shell.11.0.dll) that I can easily use to change the basic color scheme of the extension. The problem is that the standard controls (text boxes, combo boxes, check boxes) have the default WPF appearance which looks really weird.

So the question is: Is there any possibility to make standard controls in a WPF tool window of a VS extension look similar to the ones used in Visual Studio? I am aware that I could do this myself using control templates or custom controls but I really want to avoid this effort if somehow possible.

回答1:

Visual Studio 2012 use custom WPF controls. You can verify this yourself by Snoop. WPF visual tree of Visual Studio 2012 contains such controls as Microsoft.VisualStudio.PlatformUI.VsButton, Microsoft.VisualStudio.PlatformUI.Shell.Controls.TabGroupControl, Microsoft.VisualStudio.PlatformUI.SearchControl. Unfortunately, these controls are not documented and are difficult or impossible to reuse. You can only view styles of complex elements and implement similar in your code.

I create similar controls base on Winfried Lötzsch collection (now it is included in the MahApps.Metro toolkit). I also saw another collection of attractive elements. It may be useful too.

To implement support for Visual Studio themes, I use resources from Microsoft.VisualStudio.Shell.VsBrushes/VsColors and own colors. To convert icons to current theme, I use following code:

private readonly IVsUIShell5 _vsUIShell5;
private string _currentThemeId;

// cache icons for specific themes: <<ThemeId, IconForLightTheme>, IconForThemeId>
private readonly Dictionary<Tuple<string, BitmapImage>, BitmapImage> _cacheThemeIcons = 
  new Dictionary<Tuple<string, BitmapImage>, BitmapImage>();

protected override BitmapImage GetIconCurrentTheme(BitmapImage iconLight)
{
  Debug.Assert(iconLight != null);
  return _currentThemeId.ToThemesEnum() == Themes.Light ? iconLight : GetCachedIcon(iconLight);
}

private BitmapImage GetCachedIcon(BitmapImage iconLight)
{
  BitmapImage cachedIcon;
  var key = Tuple.Create(_currentThemeId, iconLight);
  if (_cacheThemeIcons.TryGetValue(key, out cachedIcon))
  {
    return cachedIcon;
  }

  var backgroundColor = FindResource<Color>(VsColors.ToolWindowBackgroundKey);
  cachedIcon = CreateInvertedIcon(iconLight, backgroundColor);
  _cacheThemeIcons.Add(key, cachedIcon);
  return cachedIcon;
}

private BitmapImage CreateInvertedIcon(BitmapImage inputIcon, Color backgroundColor)
{
  using (var bitmap = inputIcon.ToBitmapByPngEncoder())
  {
    var rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
    var bitmapData = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bitmap.PixelFormat);
    var sourcePointer = bitmapData.Scan0;
    var length = Math.Abs(bitmapData.Stride) * bitmap.Height;
    var outputBytes = new byte[length];
    Marshal.Copy(sourcePointer, outputBytes, 0, length);
    _vsUIShell5.ThemeDIBits((UInt32)outputBytes.Length, outputBytes, (UInt32)bitmap.Width,
                            (UInt32)bitmap.Height, true, backgroundColor.ToUInt());
    Marshal.Copy(outputBytes, 0, sourcePointer, length);
    bitmap.UnlockBits(bitmapData);
    return bitmap.ToPngBitmapImage();
  }
}

To inverted correctly, the icon of Light theme should be as another Visual Studio icons (with gray rim around, like this ).



回答2:

There is a themes/generic.baml in the resources of Microsoft.VisualStudio.Shell.12.dll that might contain the styles for the controls you are looking for. I used dotPeek but I don't have a plugin installed to visualize the Baml files, there a few you can try.

You should check if the license allows you to use the extracted styles though =P.