AvalonEdit:即使未聚焦,也可以突出显示当前行

17
我正在使用 AvalonEdit,并且希望即使编辑器没有焦点,用户也始终能看到插入符所在的行。为此,我找到并修改了一些代码,使用 BackgroundRenderer 来高亮当前行的背景。

不幸的是,如果我在编辑器没有焦点时更改 CaretOffset,则我的背景矩形会保持不变,停留在编辑器失去焦点时的行上。它直到编辑器重新获得焦点才会同步更新到新的当前行。

我找出了为什么会发生这种情况(只是不知道如何修复它)。根据 IBackgroundRenderer 的文档注释,“背景渲染器仅在其关联的已知图层选择绘制时才会绘制它们。例如,当光标隐藏时,光标图层中的背景渲染器将不可见。”我的背景渲染器位于 KnownLayer.Caret 上,所以我明白为什么它在编辑器没有焦点时不更新——因为光标也被隐藏了。(考虑到这一点,我实际上很惊讶我的矩形仍然可见。)

我尝试在设置 CaretOffset 后立即显式调用 textEditor.TextArea.TextView.InvalidateLayer(KnownLayer.Caret),但没有效果——我猜测调用被忽略了,因为光标被隐藏了。

在编辑器没有焦点时,强制更新当前行高亮的最佳方法是什么?


这是我的类代码。如果有更好的方法,请告诉我,我很愿意放弃目前的方式。

public class HighlightCurrentLineBackgroundRenderer : IBackgroundRenderer
{
    private TextEditor _editor;

    public HighlightCurrentLineBackgroundRenderer(TextEditor editor)
    {
        _editor = editor;
    }

    public KnownLayer Layer
    {
        get { return KnownLayer.Caret; }
    }

    public void Draw(TextView textView, DrawingContext drawingContext)
    {
        if (_editor.Document == null)
            return;

        textView.EnsureVisualLines();
        var currentLine = _editor.Document.GetLineByOffset(_editor.CaretOffset);
        foreach (var rect in BackgroundGeometryBuilder.GetRectsForSegment(textView, currentLine))
        {
            drawingContext.DrawRectangle(
                new SolidColorBrush(Color.FromArgb(0x40, 0, 0, 0xFF)), null,
                new Rect(rect.Location, new Size(textView.ActualWidth - 32, rect.Height)));
        }
    }
}

然后在我的UserControl的构造函数中,我将渲染器添加到编辑器中:

textEditor.TextArea.TextView.BackgroundRenderers.Add(
    new HighlightCurrentLineBackgroundRenderer(textEditor));

3
刚刚使用了这个,效果很棒。此外,我稍微修改了一下以适应水平滚动条,最后一行应该是:new Rect(new Point(rect.Location.X + textView.ScrollOffset.X, rect.Location.Y), new Size(textView.ActualWidth, rect.Height))); - anakic
1
在每个绘制周期中创建SolidColorBrush是不高效的。在构造函数中创建它一次,冻结它并在Draw方法中引用它。 - Alexander Smirnov
1个回答

17

这是我最终是如何解决的。

首先,我将HighlightCurrentLineBackgroundRenderer的Layer属性更改为返回KnownLayer.Background。即使编辑器没有焦点,背景层也可见,这解决了原始问题。

然而,它引入了一个新问题:只有在特定条件下才会重新绘制背景层,“插入符号移动”不是其中之一--所以现在高亮部分根本不会移动!(好吧,它确实会移动--例如,当您滚动或选择文本时。但那不是想要的行为。)但这很容易解决;每当插入符号移动时,我只需要手动使背景层失效:

textEditor.TextArea.Caret.PositionChanged += (sender, e) =>
    textEditor.TextArea.TextView.InvalidateLayer(KnownLayer.Background);

就是这样 -- 现在即使编辑器没有焦点,高亮也会更新。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接