Custom Adornments Do Not Properly Scroll With Text When Language Updated

SyntaxEditor for WPF Forum

Posted 7 years ago by \アッカリーン/
Version: 12.2.0571
Platform: .NET 4.5
Environment: Windows 8 (64-bit)
Avatar

Hi there,

After copying code directly out of one of the sample projects, the Syntax Editor does not update properly after switch out to a new language. The adornments do not stay properly aligned with the text, and fall off their mark when scrolling.

I wrote a simple sample project to demonstrate the problem. Please try running it and scroll normally, and then try scrolling after pressing the "Switch Language" button.

Please let me know if this is indeed a bug, or if there is something I'm missing that needs to be updated.

Thank you-

 

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:syntaxeditor="http://schemas.actiprosoftware.com/winfx/xaml/syntaxeditor" x:Class="SyntaxTest.MainWindow"
        Title="MainWindow" Height="600" Width="800">
    <DockPanel LastChildFill="True">
        <Button Width="100" Click="Switch_Language" Content="Switch Language" />
        <syntaxeditor:SyntaxEditor Name="SyntaxEditor" />
    </DockPanel>
</Window>

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.Text.RegularExpressions;

using ActiproSoftware.Text;
using ActiproSoftware.Text.Implementation;
using ActiproSoftware.Text.Tagging;
using ActiproSoftware.Text.Tagging.Implementation;
using ActiproSoftware.Windows.Media;
using ActiproSoftware.Text.Utility;
using ActiproSoftware.Windows.Controls.SyntaxEditor;
using ActiproSoftware.Windows.Controls.SyntaxEditor.Adornments;
using ActiproSoftware.Windows.Controls.SyntaxEditor.Adornments.Implementation;
using ActiproSoftware.Windows.Controls.SyntaxEditor.Highlighting;

namespace SyntaxTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            SyntaxEditor.Document.SetText(Enumerable.Range(0, 200).Select(a => a % 5 == 0 ? "#FF00FF\t#FF0000\r\n" : "\r\n").Aggregate((a, b) => a + b));
            SyntaxEditor.Document.Language = new MyLanguage();
        }

        private void Switch_Language(object sender, RoutedEventArgs e)
        {
            SyntaxEditor.Document.Language = new MyLanguage();
        }
    }

    public class MyLanguage : SyntaxLanguage
    {
        public MyLanguage() : base("MyLanguage")
        {
            this.RegisterService(new CodeDocumentTaggerProvider<ColorPreviewTagger>(typeof(ColorPreviewTagger)));
            this.RegisterService(new AdornmentManagerProvider<ColorPreviewAdornmentManager>(typeof(ColorPreviewAdornmentManager)));
        }
    }

    public class ColorPreviewTag : ITag
    {
        public Color Color { get; set; }
    }

    public class ColorPreviewTagger : TaggerBase<ColorPreviewTag>
    {
        public ColorPreviewTagger(ICodeDocument document) : base("ColorPreview", null, document, true) { }

        public override IEnumerable<TagSnapshotRange<ColorPreviewTag>> GetTags(NormalizedTextSnapshotRangeCollection snapshotRanges, object parameter)
        {
            if (snapshotRanges != null)
            {
                foreach (TextSnapshotRange snapshotRange in snapshotRanges)
                {
                    string text = snapshotRange.Text;
                    MatchCollection matches = Regex.Matches(text, @"\#([a-f0-9]{6}|[a-f0-9]{3})\b", RegexOptions.IgnoreCase);
                    if (matches.Count > 0)
                    {
                        foreach (Match match in matches)
                        {
                            ColorPreviewTag tag = new ColorPreviewTag();
                            tag.Color = UIColor.FromWebColor(match.Value).ToColor();
                            yield return new TagSnapshotRange<ColorPreviewTag>(
                                TextSnapshotRange.FromSpan(snapshotRange.Snapshot, snapshotRange.StartOffset + match.Index, match.Length), tag);
                        }
                    }
                }
            }
        }
    }

    public class ColorPreviewAdornmentManager : DecorationAdornmentManagerBase<IEditorView, ColorPreviewTag>
    {
        private static AdornmentLayerDefinition layerDefinition =
            new AdornmentLayerDefinition("ColorPreview", new Ordering(AdornmentLayerDefinitions.TextForeground.Key, OrderPlacement.After));

        public ColorPreviewAdornmentManager(IEditorView view) : base(view, layerDefinition) { }

        private static UIElement CreateDecorator(double width, Color color)
        {
            Rectangle rect = new Rectangle() { Width = width, Height = 3, Fill = new SolidColorBrush(color) };
            rect.Fill.Freeze();
            return rect;
        }

        protected override void AddAdornment(ITextViewLine viewLine, TagSnapshotRange<ColorPreviewTag> tagRange, TextBounds bounds)
        {
            UIElement element = ColorPreviewAdornmentManager.CreateDecorator(bounds.Width, tagRange.Tag.Color);
            Point location = new Point(Math.Round(bounds.Left), bounds.Bottom - 2);

            this.AdornmentLayer.AddAdornment(element, location, viewLine, tagRange.SnapshotRange, TextRangeTrackingModes.Default, null);
        }

        protected override void OnClosed()
        {
            this.AdornmentLayer.RemoveAllAdornments();
        }
    }
}

Comments (2)

Answer - Posted 7 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hello, the problem here is that you are overriding OnClosed but aren't calling its base implementation. That prevents the original manager from being properly detached from the view. If you call the base method, it fixes it.


Actipro Software Support

Posted 7 years ago by \アッカリーン/
Avatar

Thanks for the info! Appreciate the support here.

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

Add Comment

Please log in to a validated account to post comments.