AvalonEdit显示选择其他格式

时间:2017-02-06 22:20:10

标签: c# wpf avalonedit

我目前使用以下代码作为带有AvalonEdit LineTransformer的{​​{1}}。我希望能够通过选择突出显示当前单个搜索结果,但选择几乎不可见,因为TextEditor的格式优先于显示突出显示的文本。如何在格式化之前或之前显示突出显示的选择?

DocumentColorizingTransformer

Example of formatting showing over selection

3 个答案:

答案 0 :(得分:3)

有关AvalonEdit渲染流程,请参阅http://avalonedit.net/documentation/html/c06e9832-9ef0-4d65-ac2e-11f7ce9c7774.htm

选择图层在文本之前呈现。因此,如果文本具有背景,则它将覆盖选择背景。幸运的是,我们可以将背景设置为Brush.Transparent(或者Selection.Brush和您自己的颜色的混合)。

解决方案:我修改了SelectionColorizer代码,将选择背景重置为透明:

class SelectionColorizerWithBackground : ColorizingTransformer
{
    ICSharpCode.AvalonEdit.Editing.TextArea _textArea;

    public SelectionColorizerWithBackground(
        ICSharpCode.AvalonEdit.Editing.TextArea textArea)
    {
        if (textArea == null)
            throw new ArgumentNullException("textArea");
        this._textArea = textArea;
    }

    protected override void Colorize(ITextRunConstructionContext context)
    {
        int lineStartOffset = context.VisualLine.FirstDocumentLine.Offset;

        int lineEndOffset = context.VisualLine.LastDocumentLine.Offset +
            context.VisualLine.LastDocumentLine.TotalLength;

        foreach (var segment in _textArea.Selection.Segments)
        {
            int segmentStart = segment.StartOffset;
            if (segmentStart >= lineEndOffset)
                continue;

            int segmentEnd = segment.EndOffset;
            if (segmentEnd <= lineStartOffset)
                continue;

            int startColumn;
            if (segmentStart < lineStartOffset)
                startColumn = 0;
            else
                startColumn = context.VisualLine.ValidateVisualColumn(
                    segment.StartOffset, segment.StartVisualColumn,
                    _textArea.Selection.EnableVirtualSpace);

            int endColumn;
            if (segmentEnd > lineEndOffset)
                endColumn =
                    _textArea.Selection.EnableVirtualSpace
                        ? int.MaxValue
                        : context.VisualLine
                                 .VisualLengthWithEndOfLineMarker;
            else
                endColumn = context.VisualLine.ValidateVisualColumn(
                    segment.EndOffset, segment.EndVisualColumn,
                    _textArea.Selection.EnableVirtualSpace);

            ChangeVisualElements(
                startColumn, endColumn,
                element => {
                    element.TextRunProperties.SetBackgroundBrush(
                        System.Windows.Media.Brushes.Transparent);
                    if (_textArea.SelectionForeground != null)
                    {
                        element.TextRunProperties.SetForegroundBrush(
                            _textArea.SelectionForeground);
                    }
                });
        }
    }
}

要使用您应该执行以下操作的代码:

var lineTransformers = textEditor.TextArea.TextView.LineTransformers;

// Remove the original SelectionColorizer.
// Note: if you have syntax highlighting you need to do something else
// to avoid clearing other colorizers. If too complicated you can skip
// this step but to suffer a 2x performance penalty.
lineTransformers.Clear();

lineTransformers.Add(new ColorizeSearchResults());
lineTransformers.Add(
    new SelectionColorizerWithBackground(textEditor.TextArea));

答案 1 :(得分:2)

在我广泛尝试了我的解决方案之后,我想补充几点:

  • 虽然我上面的其他解决方案似乎有效,但是当矩形应该平铺时,你会有一些子像素假象。如果这是不可接受的,您可以实现IBackgroundRenderer。 (这恰好是我选择的解决方案。)如果你想要一些代码,你可以在这里请求,但我怀疑它是否有用。

  • BTW,,因为您的问题与搜索结果相关,很可能您可以使用https://github.com/icsharpcode/AvalonEdit/blob/697ff0d38c95c9e5a536fbc05ae2307ec9ef2a63/ICSharpCode.AvalonEdit/Search/SearchResultBackgroundRenderer.cs未修改(或修改它,如果您不想要圆角边框)

  • 您可以使用element.BackgroundBrush = Brushes.Magenta;代替element.TextRunProperties.SetBackgroundBrush(Brushes.Magenta);。 AvalonEdit似乎用一个半径为3px的矩形绘制背景。

  • 还有一个从AvalonEdit 5.01开始的RichTextColorizer。我不知道如何使用它,因为它没有在其他文件中引用。并且前一段中的(很可能不需要的)圆角矩形可能存在。

答案 2 :(得分:0)

所以,我的最终产品几乎全部基于现有的AvalonEdit SearchResultBackgroundRenderer

这与我的帖子的着色器有点不同,因为您必须手动修改搜索结果而不是为您执行此操作。但这也可以节省一些计算时间。

如果您的搜索没有使用Regex,那么您可以轻松修改SearchResult,而只是传入构造函数的起始偏移量和长度。

/// <summary>A search result storing a match and text segment.</summary>
public class SearchResult : TextSegment {
    /// <summary>The regex match for the search result.</summary>
    public Match Match { get; }

    /// <summary>Constructs the search result from the match.</summary>
    public SearchResult(Match match) {
        this.StartOffset = match.Index;
        this.Length = match.Length;
        this.Match = match;
    }
}

/// <summary>Colorizes search results behind the selection.</summary>
public class ColorizeSearchResultsBackgroundRenderer : IBackgroundRenderer {

    /// <summary>The search results to be modified.</summary>
    TextSegmentCollection<SearchResult> currentResults = new TextSegmentCollection<SearchResult>();

    /// <summary>Constructs the search result colorizer.</summary>
    public ColorizeSearchResultsBackgroundRenderer() {
        Background = new SolidColorBrush(Color.FromRgb(246, 185, 77));
        Background.Freeze();
    }

    /// <summary>Gets the layer on which this background renderer should draw.</summary>
    public KnownLayer Layer {
        get {
            // draw behind selection
            return KnownLayer.Selection;
        }
    }

    /// <summary>Causes the background renderer to draw.</summary>
    public void Draw(TextView textView, DrawingContext drawingContext) {
        if (textView == null)
            throw new ArgumentNullException("textView");
        if (drawingContext == null)
            throw new ArgumentNullException("drawingContext");

        if (currentResults == null || !textView.VisualLinesValid)
            return;

        var visualLines = textView.VisualLines;
        if (visualLines.Count == 0)
            return;

        int viewStart = visualLines.First().FirstDocumentLine.Offset;
        int viewEnd = visualLines.Last().LastDocumentLine.EndOffset;

        foreach (SearchResult result in currentResults.FindOverlappingSegments(viewStart, viewEnd - viewStart)) {
            BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder();
            geoBuilder.AlignToWholePixels = true;
            geoBuilder.BorderThickness = 0;
            geoBuilder.CornerRadius = 0;
            geoBuilder.AddSegment(textView, result);
            Geometry geometry = geoBuilder.CreateGeometry();
            if (geometry != null) {
                drawingContext.DrawGeometry(Background, null, geometry);
            }
        }
    }

    /// <summary>Gets the search results for modification.</summary>
    public TextSegmentCollection<SearchResult> CurrentResults {
        get { return currentResults; }
    }

    /// <summary>Gets or sets the background brush for the search results.</summary>
    public Brush Background { get; set; }
}

为了使用背景渲染器:

var searchColorizor = new ColorizeSearchResultsBackgroundRenderer();
textEditor.TextArea.TextView.BackgroundRenderers.Add(searchColorizor);
相关问题