I have a problem similar to the issue described in this post: How to change a ClassificationFormatDefinition
I tried implementing this in my application but when the theme is changed, the font/color changes defined by my ClassificationFormatDefinition classes don't take effect.
More background: Our Visual Studio 2015 Isolated Shell application supports a custom language with syntax highlighting using ClassificationFormatDefinition classes. We do not make the color definitions "UserVisible", but have hard-coded the formatting values (Foreground, Background, Bold, Italic).
[Export(typeof(EditorFormatDefinition))]
[ClassificationType(ClassificationTypeNames = "requiredtag")]
[Name("requiredtag")]
[UserVisible(false)]
[Order(After = Priority.Default, Before = Priority.High)]
internal sealed class RequiredTagFormat : ClassificationFormatDefinition
{
public RequiredTagFormat()
{
this.DisplayName = "requiredtag";
this.ForegroundColor = Colors.Green;
}
}
In order to support the Light, Blue and Dark themes, I have created a helper class with a dictionary that defines the colors used by the three themes.
internal enum Themes
{
Light = 0,
Blue = 1,
Dark = 2,
};
internal static class ThemeHelper
{
private static Dictionary<Themes, ColorScheme> ColorSchemes = new Dictionary<Themes, ColorScheme>();
internal static Themes ActiveTheme { get; set; } = Themes.Blue;
internal static ColorScheme ActiveColorScheme
{
get
{
return ColorSchemes[ActiveTheme];
}
}
The ClassificationFormatDefinition classes are initialized using this helper class based on the current theme. Everything works great when the application is launched - the current Theme setting is recognized and all colors are correct.
[Export(typeof(EditorFormatDefinition))]
[ClassificationType(ClassificationTypeNames = "requiredtag")]
[Name("requiredtag")]
[UserVisible(false)]
[Order(After = Priority.Default, Before = Priority.High)]
internal sealed class RequiredTagFormat : ClassificationFormatDefinition, IChangeableClassificationFormatDefinition
{
public RequiredTagFormat()
{
this.DisplayName = "requiredtag";
this.ForegroundColor = ThemeHelper.ActiveColorScheme.RequiredTag.Foreground ?? this.ForegroundColor;
this.BackgroundColor = ThemeHelper.ActiveColorScheme.RequiredTag.Background ?? this.BackgroundColor;
this.IsItalic = ThemeHelper.ActiveColorScheme.RequiredTag.Italic;
this.IsBold = ThemeHelper.ActiveColorScheme.RequiredTag.Bold;
}
}
When the user changes the theme, however, all of the colors in the application are updating except the syntax highlightling for the custom language. From the post above, I thought implementing the CacheManager code would cause the ClassificationFormatDefinition classes to be re-initialized and therefore take on the colors for the new theme, but after implementing the CacheManager code in the VSColorTheme.ThemeChanged event handler, it had no detectable effect.
I tried adding an interface to the ClassificationFormatDefinition classes with a method that I could call to update the font/color settings for each class based on the current theme, keep track of the class isntances in the theme helper, and then invoke that method for each class when I handle the VSColorTheme.ThemeChanged event in the application. All of this code is working great. However, the syntax highlighting still does not change.
[Export(typeof(EditorFormatDefinition))]
[ClassificationType(ClassificationTypeNames = "requiredtag")]
[Name("requiredtag")]
[UserVisible(false)]
[Order(After = Priority.Default, Before = Priority.High)]
internal sealed class RequiredTagFormat : ClassificationFormatDefinition, IChangeableClassificationFormatDefinition
{
public RequiredTagFormat()
{
this.DisplayName = "requiredtag";
ThemeHelper.FormatDefinitions.Add(this);
Update();
}
public void Update()
{
this.ForegroundColor = ThemeHelper.ActiveColorScheme.RequiredTag.Foreground ?? this.ForegroundColor;
this.BackgroundColor = ThemeHelper.ActiveColorScheme.RequiredTag.Background ?? this.BackgroundColor;
this.IsItalic = ThemeHelper.ActiveColorScheme.RequiredTag.Italic;
this.IsBold = ThemeHelper.ActiveColorScheme.RequiredTag.Bold;
}
}
When I attempted to implement the UpdateFont() method from the above linked post in my project package, not only did it not resolve the issue, but the language syntax highlighting stopped working completely and generated multiple InvalidCastExceptions (logged in the ActivityLog.xml file) any time I open a code window!
<entry>
<record>423</record>
<time>2020/06/09 18:55:10.974</time>
<type>Error</type>
<source>Editor or Editor Extension</source>
<description>System.InvalidCastException: Unable to cast object of type 'System.Reflection.RuntimeMethodInfo' to type 'System.Reflection.ConstructorInfo'.
 at Microsoft.VisualStudio.Composition.Reflection.ResolverExtensions.Resolve(ConstructorRef constructorRef)
 at Microsoft.VisualStudio.Composition.RuntimeComposition.RuntimePart.get_ImportingConstructor()
 at Microsoft.VisualStudio.Composition.RuntimeExportProviderFactory.RuntimeExportProvider.RuntimePartLifecycleTracker.CreateValue()
 at Microsoft.VisualStudio.Composition.ExportProvider.PartLifecycleTracker.Create()
 at Microsoft.VisualStudio.Composition.ExportProvider.PartLifecycleTracker.MoveNext(PartLifecycleState nextState)
 at Microsoft.VisualStudio.Composition.ExportProvider.PartLifecycleTracker.MoveToState(PartLifecycleState requiredState)
 at Microsoft.VisualStudio.Composition.ExportProvider.PartLifecycleTracker.GetValueReadyToExpose()
 at Microsoft.VisualStudio.Composition.RuntimeExportProviderFactory.RuntimeExportProvider.<>c__DisplayClass15_0.<GetExportedValueHelper>b__0()
 at Microsoft.VisualStudio.Composition.DelegateServices.<>c__DisplayClass2_0`1.<As>b__0()
 at System.Lazy`1.CreateValue()
--- End of stack trace from previous location where exception was thrown ---
 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 at System.Lazy`1.get_Value()
 at Microsoft.VisualStudio.Text.Tagging.Implementation.TagAggregator`1.GatherTaggers(ITextBuffer textBuffer)</description>
</entry>
This leads me to believe the issue is still with caching, but I am at a loss to figure out how to get these fonts/colors to dynamically update when the theme is changed.