【发布时间】:2014-01-09 20:50:11
【问题描述】:
假设我有 2 个文本指针。一个指向词首,另一个指向词尾。
我想在单词周围画一个像素边框。我该怎么办?当用户键入或滚动时,边框应与单词绑定并随之移动。
我已经用 DrawingBrush 尝试了 TextDecorations,但没有找到任何可用的东西。
【问题讨论】:
标签: c# wpf richtextbox border
假设我有 2 个文本指针。一个指向词首,另一个指向词尾。
我想在单词周围画一个像素边框。我该怎么办?当用户键入或滚动时,边框应与单词绑定并随之移动。
我已经用 DrawingBrush 尝试了 TextDecorations,但没有找到任何可用的东西。
【问题讨论】:
标签: c# wpf richtextbox border
我也做过类似的事情,只是在 TextBox 中加了下划线。校长似乎大体相同。
添加一个 AdornerDecorator,其中包含您的 RichTextBox,但在 ScrollViewer 内。
<Border ...>
<ScrollViewer ... >
<AdornerDecorator>
<RichTextBox
x:Name="superMagic"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
BorderBrush="{x:Null}"
BorderThickness="0"
...
/>
</AdornerDecorator>
</ScrollViewer>
</Border>
创建一个 Adorner 来渲染矩形并将其添加到 AdornerLayer
void HostControl_Loaded(object sender, RoutedEventArgs e)
{
_adorner = new RectangleAdorner(superMagic);
AdornerLayer layer = AdornerLayer.GetAdornerLayer(superMagic);
layer.Add(_adorner);
}
装饰器应该挂钩 RichTextBox 的 TextChanged 事件。您需要做的就是通过调度程序使用DispatcherPriority.Background 调用InvalidateVisuals(),以确保它在文本框之后呈现。我不知道这是否是 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);
}
// ...
}
覆盖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));
}
注意:虽然原始代码运行良好,但我很久以前就写过了,还没有测试我对这个答案的改编。它至少应该帮助你走上正确的道路。
此外,这不处理单词跨行拆分的情况,但不应该太难满足。
【讨论】: