How to draw border around a word in RichTextBox?

拜拜、爱过 提交于 2019-12-18 04:43:27

问题


Let's say I have 2 TextPointers. One pointing at the beginning of a word and the other at the end of the word.

I would like to draw single pixel border around the word. How would I go about this? The border should be tied to the word and move with it when user types or scrolls..

I already tried TextDecorations with DrawingBrush but couldn't come up with anything usable.


回答1:


I have done something similar, only underlining text in a TextBox. The principal seems to be mostly the same.

  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));
    }
    

Note: Although the original code worked well, I wrote it a long time ago and have not tested my adaptions for this answer. It should at least help put you on the right path.

Also, this does not handle cases where the word is split across lines, but shouldn't be too hard to cater for.



来源:https://stackoverflow.com/questions/6158291/how-to-draw-border-around-a-word-in-richtextbox

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!