2011-05-27 41 views
9

Digamos que tengo 2 TextPointers. Uno apuntando al comienzo de una palabra y el otro al final de la palabra.¿Cómo dibujar el borde alrededor de una palabra en RichTextBox?

Me gustaría dibujar el borde de un solo píxel alrededor de la palabra. ¿Cómo voy a hacer esto? La frontera debe estar vinculada a la palabra y desplaza con ella al usuario escribe o se desplaza ..

ya he tratado con TextDecorations DrawingBrush pero no pudieron llegar a nada utilizable.

Respuesta

7

He hecho algo similar, solo subrayando texto en un TextBox. El director parece ser más o menos el mismo.

  1. Agregue un AdornerDecorator que contenga su RichTextBox pero dentro de ScrollViewer.

    <Border ...> 
        <ScrollViewer ... > 
         <AdornerDecorator> 
          <RichTextBox 
           x:Name="superMagic" 
           HorizontalScrollBarVisibility="Hidden" 
           VerticalScrollBarVisibility="Hidden" 
           BorderBrush="{x:Null}" 
           BorderThickness="0" 
           ... 
           /> 
         </AdornerDecorator> 
        </ScrollViewer> 
    </Border> 
    
  2. Crear Adorner para hacer que el rectángulo y añadirlo a la AdornerLayer

    void HostControl_Loaded(object sender, RoutedEventArgs e) 
    { 
        _adorner = new RectangleAdorner(superMagic); 
    
        AdornerLayer layer = AdornerLayer.GetAdornerLayer(superMagic); 
        layer.Add(_adorner); 
    } 
    
  3. El adorner debe enlazar el evento TextChanged de RichTextBox. Todo lo que necesita hacer es llamar al InvalidateVisuals() a través del despachador usando DispatcherPriority.Background para asegurarse de que se represente después del cuadro de texto. No sé si es un problema para el RichTextBox, pero obtener las coordenadas del personaje de un TextBox solo es posible si se ha procesado al menos una vez desde que se modificó por última vez.

    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. Anulación Adorner.OnRender() para dibujar el cuadro utilizando TextPointer.GetCharacterRect() para obtener las coordenadas.

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

Nota: Aunque el código original funcionó bien, lo escribí hace mucho tiempo y no he probado mis adaptaciones para esta respuesta. Al menos debería ayudarlo a ponerse en el camino correcto.

Además, esto no se aplica a los casos en que la palabra se divide entre líneas, pero no debería ser demasiado difícil de atender.

+0

Genial, voy a probar esto. – Kugel

+0

¡Funciona perfecto! :) – JanDotNet

Cuestiones relacionadas