Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
I wanted to define some custom colors for an extension I'm writing. It's a pretty convoluted process, so I created some wrapper classes and thought it belongs in the toolkit, so here it is. 😁
Defining Custom Font and Color Settings
There are three parts to defining custom font and color settings.
Font And Color Provider
You tell Visual Studio about the custom font and color definitions by using a class inheriting from
BaseFontAndColorProvider
:ℹ️ Visual Studio uses a GUID to identify the provider, so make sure you add a
GuidAttribute
to the provider class.The provider will find all categories defined in the same assembly as itself, and tell Visual Studio about them.
There are two things you need to do with the provider:
ProvideFontsAndColorsAttribute
:If you don't do both of these things, then Visual Studio won't know about your font and colors.
Font And Color Category
A category defines a default font and the colors that can be configured by the user. You define a category by inheriting from
BaseFontAndColorCategory<T>
. Just like commands and tool windows, theT
type is the type of the inheriting class.ℹ️ Visual Studio uses a GUID to identify the category, so make sure you add a
GuidAttribute
to the category class.Default Font
When you define a category, you can specify a default font or you can let it use an "Automatic" font. The "Automatic" font is the font that is used by Visual Studio for most of the UI elements. It can be configured by setting the font for the Environment category.
Color Definitions
The colors for a category are specified by defining properties of type
ColorDefinition
on the category class. The category will find these properties and tell Visual Studio about the colors.Color Definitions
A
ColorDefinition
defines the default values for an item that appears in the Fonts and Colors options page. You can also control what a user can customize about the item.Every color needs a name. You can optionally specify a localized name and a description, though I have no idea where the description is shown.
You can specify the default foreground and background colors, and the default font style. You can also specify options that control what the user can customize. For example, you can prevent a bold font from being used, or prevent custom colors being selected, or prevent the background or foreground color from being customized at all.
There is also a line style and "marker visual style", though I'm not sure where they are used in Visual Studio. They're part of the underlying
AllColorableItemInfo
that Visual Studio uses, so I figured it was best to include them just in case someone needed them.Colors
A specific color is specified using the
VisualStudioColor
class. There are five different ways that you can create aVisualStudioColor
.Indexed
"Indexed" colors are the predefined colors like Yellow, Red, Green, etc.
VsColor
This allows you to use a color that is defined by the Visual Studio theme. The theme colors are defined in three separate enums:
__VSSYSCOLOREX
,__VSSYSCOLOREX2
and__VSSYSCOLOREX3
. If you're trying to match other parts of Visual Studio, this is probably what you want to be using.SysColor
This creates a color using a Windows system color. There's no enum for the system colors, but you can find their values here. These types of colors probably aren't that useful because they don't take into account the Visual Studio theme. You're better off using the
VsColor
method.Rgb
This lets you create any color that you want. You can use red, green and blue components, or use a
System.Windows.Media.Color
.Automatic
This defines an "automatic" color. I think is the best way to use them:
ColorDefinition
, set theAutomaticBackground
color to aVsColor
(for example,VisualStudioColor.VsColor(__VSSYSCOLOREX.VSCOLOR_ENVIRONMENT_BACKGROUND)
).DefaultBackground
color toAutomatic
.When you select Automatic for the color in the Fonts and Colors options page, the
VSCOLOR_ENVIRONMENT_BACKGROUND
will be used.Getting Fonts and Colors
Once you've defined the font and color categories, you'll probably want to get the actual font and color values that the user has customized. This can be done via the
VS.FontsAndColors
object.To get the configured font and colors for a category, use the
GetConfiguredFontAndColorsAsync
method. Specify the type of the category as a generic parameter:The
ConfiguredFontAndColorSet<T>
provides access to the font and each of the color definitions. This is a "live" object - if the user customizes the font or color, the changes will be reflected in this object - so you don't need to get a new set each time you want to get the configured font or colors. Just make sure you dispose of it when you no longer need it.Font
The font is available in the
Font
property as aConfiguredFont
. If the user customizes the font for the category, this object will be updated with the new font family and size.This type is geared towards being used in WPF. It implements
INotifyPropertyChanged
, so you can bind directly to it in XAML.Family
is aFontFamily
object. If you're not using the font in WPF, then the font family is also available as a string via theFamilyName
property.ℹ️ The font can be "automatic". In that case, the
Family
property will be null and theFamilyName
property will be the same asFontDefinition.Automatic.FamilyName
.Colors
The configured colors can be accessed via the
GetColor
method. You pass in theColorDefinition
of the color that you need. TheConfiguredFontAndColorSet<T>
conveniently has aCategory
property that provides access to the category, so you can use that to access theColorDefinition
objects.The color is a
ConfiguredColor
. Just like theConfiguredFont
, this object will update if the user customizes the color settings. It also implementsINotifyPropertyChanged
, so you can bind directly to it in XAML as well.Brushes are available from the
ForegroundBrush
andBackgroundBrush
properties. If you're not using it in WPF, there's alsoForegroundColor
andBackgroundColor
properties that provide the color as aColor
object.The font style is also available. This is a
FontStyle
enum, but it essentially defines whether or not the font should be bold, as that's the only thing the user can customize. If you're using it in WPF, there's also aFontWeight
property that you can bind to.Events
As mentioned above, the
ConfiguredFont
andConfiguredColor
classes implementINotifyPropertyChanged
, so you could add event handlers to them to detect when fonts and colors are customized, but there is an easier way. TheConfiguredFontAndColorSet<T>
has two events that are raised whenever the font or any of the colors are changed:FontChanged
is raised when something about the font is changed (font family or size).ColorChanged
is raised when something about aConfiguredColor
is changed (foreground, background or font style). The specificConfiguredColor
that changed is included in the event arguments.Code Analyzers
Since there are a few things that you need to do to get Visual Studio to be aware of the font and color definitions, I've also added some code analyzers to detect mistakes.
CVST006
GuidAttribute
. Visual Studio identifies the providers by GUID, so it's important that the provider has an explicitly defined GUID.CVST007
GuidAttribute
. Just like providers, the categories are also identified by GUID.CVST008
CSVT009
ProvideFontsAndColorsAttribute
to your package.CVST010
ProvideFontsAndColorsAttribute
to your package, but you haven't calledRegisterFontAndColorProvidersAsync
when initializing the package.Demo
And to finish things off, the demo extension has an example of using font color definitions. Use View -> Other Windows -> Fonts and Colors Window to open the tool window. This window has four boxes. Each box uses a custom color definition.
In the Fonts and Colors options page, select the "Fonts and Colors Demo" item in the dropdown (it's towards the bottom). From there you can customize the four colors that are used on the tool window. When you save, the tool window will update with the new colors, and shows the events that were emitted.