【问题标题】:How to draw border around a word in RichTextBox?如何在 RichTextBox 中的单词周围绘制边框?
【发布时间】:2014-01-09 20:50:11
【问题描述】:

假设我有 2 个文本指针。一个指向词首,另一个指向词尾。

我想在单词周围画一个像素边框。我该怎么办?当用户键入或滚动时,边框应与单词绑定并随之移动。

我已经用 DrawingBrush 尝试了 TextDecorations,但没有找到任何可用的东西。

【问题讨论】:

    标签: c# wpf richtextbox border


    【解决方案1】:

    我也做过类似的事情,只是在 TextBox 中加了下划线。校长似乎大体相同。

    1. 添加一个 AdornerDecorator,其中包含您的 RichTextBox,但在 ScrollViewer 内。

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

      void HostControl_Loaded(object sender, RoutedEventArgs e)
      {
          _adorner = new RectangleAdorner(superMagic);
      
          AdornerLayer layer = AdornerLayer.GetAdornerLayer(superMagic);
          layer.Add(_adorner);
      }
      
    3. 装饰器应该挂钩 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);
          }
      
          // ...
      }
      
    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));
      }
      

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

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

    【讨论】:

    • 完美运行! :)
    猜你喜欢
    • 2011-01-19
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-10
    相关资源
    最近更新 更多