如何在RichTextBox中为单词绘制边框?

10

假设我有两个 TextPointer,一个指向单词的开头,另一个指向单词的结尾。

我想在单词周围绘制一像素的边框。我该怎么做?边框应与单词相关联,并随着用户键入或滚动而移动。

我已经尝试使用 DrawingBrush 的 TextDecorations,但没有找到可用的内容。

1个回答

7
我之前做过类似的事情,只是在文本框中加下划线。原则上大部分都相同。
  1. Add an AdornerDecorator containing your RichTextBox but inside a ScrollViewer.

    <Border ...>
        <ScrollViewer ... >
            <AdornerDecorator>
                <RichTextBox
                    x:Name="superMagic"
                    HorizontalScrollBarVisibility="Hidden"
                    VerticalScrollBarVisibility="Hidden"
                    BorderBrush="{x:Null}"
                    BorderThickness="0"
                    ...
                    />
            </AdornerDecorator>
        </ScrollViewer>
    </Border>
    
  2. Create an Adorner to render the rectangle and add it to the AdornerLayer

    void HostControl_Loaded(object sender, RoutedEventArgs e)
    {
        _adorner = new RectangleAdorner(superMagic);
    
        AdornerLayer layer = AdornerLayer.GetAdornerLayer(superMagic);
        layer.Add(_adorner);
    }
    
  3. The adorner should hook the TextChanged event of the RichTextBox. All you need to do is call InvalidateVisuals() via the dispatcher using DispatcherPriority.Background to ensure it is rendered after the text box. I don't know if it's an issue for the RichTextBox, but getting the character coordinates from a TextBox is only possible if it has been rendered at least once since it's content last changed.

    class RectangleAdorner : Adorner
    {
        public RectangleAdorner(RichTextBox textbox)
            : base(textbox)
        {
            textbox.TextChanged += delegate
            {
                SignalInvalidate();
            };
        }
    
        void SignalInvalidate()
        {
            RichTextBox box = (RichTextBox)this.AdornedElement;
            box.Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)InvalidateVisual);
        }
    
        // ...
    }
    
  4. Override Adorner.OnRender() to draw the box using TextPointer.GetCharacterRect() to get the coordinates.

    protected override void OnRender(DrawingContext drawingContext)
    {
        TextPointer start;
        TextPointer end;
    
        // Find the start and end of your word
        // Actually, if you did this in the TextChanged event handler,
        // you could probably save some calculation time on large texts
        // by considering what actually changed relative to an earlier
        // calculation. (TextChangedEventArgs includes a list of changes
        //  - 'n' characters inserted here, 'm' characters deleted there).
    
        Rect startRect = start.GetCharacterRect(LogicalDirection.Backward);
        Rect endRect = end.GetCharacterRect(LogicalDirection.Forward);
    
        drawingContext.DrawRectangle(null, pen, Rect.Union(startRect, endRect));
    }
    

注意:虽然原始代码运行良好,但我很久以前就写过它,并且没有为此答案测试我的改编。它至少应该帮助您找到正确的方向。

另外,这不处理单词跨行的情况,但不应该太难迎合。


完美运行! :) - JanDotNet

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