How to change syntax colors at run time

SyntaxEditor for WPF Forum

Posted 5 years ago by Matt Gerrans
Version: 14.2.0610
Avatar

I don't see in any of the examples where classification type colors are changed at run time.    Is there one there somewhere?

It looks like I need to find the classification type provider, something like:

var classificationTypeProvider = syntaxEditor.Document.Language.GetService<MyLanguageClassificationTypeProvider>();

Then it looks like it has classificationTypeProvider.Registry.HighlightingStyles collection, but its not clear how to map that correctly to the classification types.

Maybe this isn't the right way to update the colors/styles for a classification type dynamically, anyway?

Comments (10)

Posted 5 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Matt,

Is something like our "Highlighting Style Viewer" QuickStart what you are looking for?


Actipro Software Support

Posted 5 years ago by Matt Gerrans
Avatar

Ah yes, missed that.   The binding in the sample doesn't seem to fully work, as I can change the values, but they don't seem to have any effect.

Also, I am hosting the syntax editor in Winforms, so I have to unravel all the XAML magic in the sample.    

I guess it might translate into something like this:

var color = Colors.Aqua;
var targetClassification = "foo";

var types = AmbientHighlightingStyleRegistry.Instance.ClassificationTypes.ToList();
var styles = AmbientHighlightingStyleRegistry.Instance.HighlightingStyles.ToList();
for (int i = 0; i < types.Count; i++)
{
   var classificationType = types[i];
   if (classificationType.Key == targetClassification)
      styles[i].Foreground = new SolidColorBrush(color);
}

I think something analogous to the UpdateSourceTrigger also needs to be done, though...



Posted 5 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

I just tried the sample here and it seemed to work fine.  Make sure you are altering display items that are showing in the sample editor at the bottom.  For instance, if you change the Keyword foreground from blue to red, you see that reflected in the editor at the bottom left.


Actipro Software Support

Posted 5 years ago by Matt Gerrans
Avatar

I'm trying to do this in Winforms code like this:

var key = "Concept";
var wpfColor = System.Windows.Media.Color.FromArgb(color.A, color.R, color.G, color.B);
var wpfBrush = wpfColor.ToSolidColorBrush();

var types = AmbientHighlightingStyleRegistry.Instance.ClassificationTypes;
var styles = AmbientHighlightingStyleRegistry.Instance.HighlightingStyles;

styles.Zip(types, (h, t) => new Tuple<IClassificationType, IHighlightingStyle>(t, h))
   .Single(p => p.Item1.Key == key).Item2.Foreground = wpfBrush;

 It seems to be matching the wrong classification though.   I was assuming that the ClassificationTypes collection and the HighlightingStyles collection are parallel to one anther.   Is this not correct?   Given a classification, how do I find it's corresponding style?

Posted 5 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Matt,

You want to register new styles with code like this:

AmbientHighlightingStyleRegistry.Instance.Register(ClassificationTypes.Comment, style, true);

This sample code line assumes you are updating the default Comment classification type.  It could be any of the classification types from your "types" variable above though.

Also I believe you can just update the existing IHighlightingStyle instances (like in your "styles" variable) and they should update in attached editors.  That's effectively what the QuickStart I mentioned is doing.


Actipro Software Support

Posted 5 years ago by Matt Gerrans
Avatar

Okay, I using the unreregiser/register like this works:

        public void SetClassificationForegroundColor(string key, SolidColorBrush brush)
        {
            var classificationTypeProvider = new CmdVarClassificationTypeProvider();

            var types = new List<IClassificationType>
            {
                classificationTypeProvider.Default,
                classificationTypeProvider.Concept,
                classificationTypeProvider.Criteria
            };

            var classificationType = types.FirstOrDefault(t => t.Key == key);
            
            if (classificationType != null)
            {
                var registry = AmbientHighlightingStyleRegistry.Instance;
                registry.Unregister(classificationType);
                registry.Register(classificationType, new HighlightingStyle(brush));
            }
        }

I think the Unregister() is not strictly needed, either.  The documentation says "Attempts to adds an IHighlightingStyle for the specified IClassificationType into the registry, as long as there is no existing IHighlightingStyle registered with the same IClassificationType," but in fact, when I try it without the Unregister() call, it still works; that is, it updates/replaces the old style with the new one.   So maybe the doc should say "Adds an IHighlightingStyle for the specified IClassificationType into the registry.  If there is an existing IHighlightingStyle registered with the same IClassificationType it is replaced."

I guess ClassificationTypes is just a set of common types that people might use?    I need to use my own specific CmdVarClassificationTypeProvider that you see above (as you might imagine, the key could be "Default" "Concept" or "Criteria" and is what we're using to serialize the settings also).  Is there are more elegant way to match the key to get the corresponding classification type?

Thanks!

Posted 5 years ago by Matt Gerrans
Avatar

Scratch that comment about the Unregister being unnecessary.    It turns out to be correct they way I have it up there -- with Unregister().

Posted 5 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

The documentation is correct for that method, however I think what happens is that you are creating new classification types each time here instead of reusing existing instances. Thus the check for an existing entry is failing. Of note, there is a Register method overload that lets you say whether to force an override. You normally would want to use that (passing true for override) and not do Unregister before.

I would also recommend using static instances of your classification types.  Either that or use the registry's GetClassificationType method where you pass in the string key to see if there is an existing entry with that key.  If there is an existing entry, pass that to the Register method instead, again with that over overload that can force overwriting.

Yes, our ClassificationTypes class is common types.


Actipro Software Support

Posted 5 years ago by Matt Gerrans
Avatar

I'm a little mystified about how the registration works; it looks like the RegisterAll() method just returns an array of IClassificationTypes, but doens't do any registering activity.   

The sample has this:

   // Register the default display item classification types on the ambient and custom registries
   new DisplayItemClassificationTypeProvider().RegisterAll();
   new DisplayItemClassificationTypeProvider(consoleWindowRegistry).RegisterAll();

The comment talks about the ambient registry, but I don't see any reference to it in the method, other than it being added to the combo box.

It isn't clear to me if I should use AmbientHighlightingStyleRegistry.Instance.Register() or "new CmdVarClassificationTypeProvider().RegisterAll()".   Based on your suggestion, I changed to this, which seems to be working fine:

static readonly CmdVarClassificationTypeProvider classificationTypeProvider = new CmdVarClassificationTypeProvider();
static readonly List<IClassificationType> ClassificationTypes = new List<IClassificationType>
    {
        classificationTypeProvider.Default,
        classificationTypeProvider.Concept,
        classificationTypeProvider.Criteria,
        classificationTypeProvider.All,
        classificationTypeProvider.Optional,
        classificationTypeProvider.Required,
        classificationTypeProvider.Pipe
    };

//...

public void SetClassificationForegroundColor(string key, SolidColorBrush brush)
{
    var classificationType = ClassificationTypes.FirstOrDefault(t => t.Key == key);

    if (classificationType != null)
    {
        var registry = AmbientHighlightingStyleRegistry.Instance;
        registry.Register(classificationType, new HighlightingStyle(brush), true);
    }
}
Posted 5 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

The DisplayItemClassificationTypeProvider constructor without a parameter will target the AmbientHighlightingStyleRegistry.  The RegisterAll method will make sure whichever target registry has that classification type provider's classification types registered with an appropriate style.

Your code looks fine for SetClassificationForegroundColor.


Actipro Software Support

The latest build of this product (v2019.1 build 0683) was released 1 month ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.