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

Kug*_*gel 10 c# wpf border richtextbox

假设我有2个TextPointers.一个指向一个单词的开头,另一个指向单词的结尾.

我想在单词周围绘制单个像素边框.我该怎么做?当用户输入或滚动时,边框应该与单词绑定并随之移动.

我已经尝试过使用DrawingBrush的TextDecorations但是无法提供任何可用的东西.

Bri*_*hle 7

我做了类似的事情,只在TextBox中加下了文字.校长似乎大致相同.

  1. 添加包含RichTextBox但在ScrollViewer中的AdornerDecorator.

    <Border ...>
        <ScrollViewer ... >
            <AdornerDecorator>
                <RichTextBox
                    x:Name="superMagic"
                    HorizontalScrollBarVisibility="Hidden"
                    VerticalScrollBarVisibility="Hidden"
                    BorderBrush="{x:Null}"
                    BorderThickness="0"
                    ...
                    />
            </AdornerDecorator>
        </ScrollViewer>
    </Border>
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创建一个Adorner来渲染矩形并将其添加到AdornerLayer

    void HostControl_Loaded(object sender, RoutedEventArgs e)
    {
        _adorner = new RectangleAdorner(superMagic);
    
        AdornerLayer layer = AdornerLayer.GetAdornerLayer(superMagic);
        layer.Add(_adorner);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 装饰器应该挂钩RichTextBox的TextChanged事件.您需要做的就是InvalidateVisuals()通过调度程序调用DispatcherPriority.Background以确保它在文本框之后呈现.我不知道这是否是一个问题RichTextBox,但是TextBox只有当它的内容最后一次更改时,才能获得至少一次的字符坐标.

    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);
        }
    
        // ...
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 覆盖Adorner.OnRender()以使用框来绘制TextPointer.GetCharacterRect()坐标.

    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));
    }
    
    Run Code Online (Sandbox Code Playgroud)

注意:虽然原始代码运行良好,但我很久以前就写过了,并没有测试我对这个答案的适应性.它至少应该帮助你走上正确的道路.

此外,这不处理单词跨行分割的情况,但不应该太难以满足.