假设我有两个 TextPointer,一个指向单词的开头,另一个指向单词的结尾。
我想在单词周围绘制一像素的边框。我该怎么做?边框应与单词相关联,并随着用户键入或滚动而移动。
我已经尝试使用 DrawingBrush 的 TextDecorations,但没有找到可用的内容。
假设我有两个 TextPointer,一个指向单词的开头,另一个指向单词的结尾。
我想在单词周围绘制一像素的边框。我该怎么做?边框应与单词相关联,并随着用户键入或滚动而移动。
我已经尝试使用 DrawingBrush 的 TextDecorations,但没有找到可用的内容。
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>
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);
}
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);
}
// ...
}
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));
}
注意:虽然原始代码运行良好,但我很久以前就写过它,并且没有为此答案测试我的改编。它至少应该帮助您找到正确的方向。
另外,这不处理单词跨行的情况,但不应该太难迎合。