2011-03-25 5 views

Respuesta

4

ACTUALIZACIÓN:

Traté de crear un ejemplo lo más mínimo posible. En escenarios más complejos, tendrás que extender esto. Aquí es como se ve:

enter image description here

este es el xaml correspondiente:

<AdornerDecorator> 
    <StackPanel> 
     <TextBlock> 
      <Run>this is normal Text</Run><LineBreak/> 
      <Run local:DiagonalStrikeThroughAdorner.StrikeThroughBrush="Red">Some text with diagonal decoration</Run><LineBreak/> 
      <Run>more normal text yeah</Run> 
     </TextBlock> 
     <FlowDocumentScrollViewer> 
      <FlowDocument> 
       <Paragraph> 
        <Run>this is normal Text</Run> 
        <LineBreak/> 
        <Run local:DiagonalStrikeThroughAdorner.StrikeThroughBrush="Red">Some text with diagonal decoration</Run> 
        <LineBreak/> 
        <Run>more normal text yeah</Run> 
       </Paragraph> 
      </FlowDocument> 
     </FlowDocumentScrollViewer> 
    </StackPanel> 
</AdornerDecorator> 

y ese es el código subyacente:

public class DiagonalStrikeThroughAdorner : Adorner 
{ 
    private readonly Inline _inline; 
    private readonly Pen _pen; 

    public DiagonalStrikeThroughAdorner(UIElement adornedElement, Inline inline, Brush brush) : base(adornedElement) 
    { 
     _inline = inline; 
     _pen = new Pen(brush, 2); 
    } 

    protected override void OnRender(DrawingContext drawingContext) 
    { 

     if(!(_inline.ContentStart.HasValidLayout && _inline.ContentEnd.HasValidLayout)) 
      return; 
     var startrect = _inline.ContentStart.GetCharacterRect(LogicalDirection.Forward); 
     var endrect = _inline.ContentEnd.GetCharacterRect(LogicalDirection.Backward); 

     drawingContext.DrawLine(_pen,startrect.BottomLeft,endrect.TopRight); 
    } 

    public static Brush GetStrikeThroughBrush(DependencyObject obj) 
    { 
     return (Brush)obj.GetValue(StrikeThroughBrushProperty); 
    } 

    public static void SetStrikeThroughBrush(DependencyObject obj, Brush value) 
    { 
     obj.SetValue(StrikeThroughBrushProperty, value); 
    } 

    public static readonly DependencyProperty StrikeThroughBrushProperty = 
     DependencyProperty.RegisterAttached("StrikeThroughBrush", typeof(Brush), typeof(DiagonalStrikeThroughAdorner), new UIPropertyMetadata((o, args) => 
      { 
       if(!(o is TextElement)) return; 
       var parent = ((TextElement)o).Parent; 
       while (parent is FrameworkContentElement) 
        parent = ((FrameworkContentElement) parent).Parent; 
       if (parent == null || !(parent is Visual)) return; 
       var adornerLayer = AdornerLayer.GetAdornerLayer((Visual) parent); 
       if(adornerLayer == null) return; 
       adornerLayer.Add(new DiagonalStrikeThroughAdorner((UIElement) parent,o as Inline,(Brush) args.NewValue));      
      })); 

} 

divertirse!

mensaje original:

esto es en general bastante duro. He logrado adjuntar un adorno a elementos específicos en documentos de flujo, pero hay muchos casos especiales a considerar. por ejemplo: ¿qué se supone que sucederá si ese Inline está envuelto? Además: si este documento de flujo se encuentra en un richtextbox, sus elementos internos siguen reorganizando ejecuciones (uniéndolos o separándolos), lo que prácticamente arruina todo. tienes que configurar las cosas cuidadosamente

Por favor, elabore más sobre dónde va a estar este en línea. ¿Dentro de FlowdocumentScrollviewer? ¿O un TextBlock? O un Richtextbox? Como tiene que adjuntar el adorno al FrameworkElement regulador (como probablemente ya haya notado que no puede adjuntar un Adorner a FrameworkContentElement directamente) necesitamos saber dónde se encuentra el en línea.

Describiré la ruta general de cómo lograr esto: cree una propiedad adjunta que va a crear el adorno. la propiedad adjunta se establece en la línea que se va a adornar. el adornador guarda una referencia al en línea y se adjunta al FrameworkElement que lo rige. subscibe a layoutupdated en ese frameworkelement y hacer un InvalidateVisual en Adorner. Los adornos OnRender trazan la línea con coordenadas dependiendo de los rectángulos ContentStart y ContentEnd GetCharacterRect. hecho.

+0

¡oh! ¡parece una ruta larga! Mi plan inicial era usarlo como una ejecución, pero ahora elegiría el "Inside FlowDocument". –

+0

@shayan, ¡mira mi actualización! –

+0

¡guau! y para un efecto diagonal, tiene sentido mantener la parte entera no rompible (en envoltura). Muchas gracias. –

0

poner el texto en un lienzo o Cuadrícula (algo que permite que los controles se superponen) y añadir un objeto de línea con su X puntos/Y unidos a la posición TextBlock

Algo como esto:

<Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Yellow"> 
    <TextBlock x:Name="TestText" Text="This is a Test" /> 
    <Line X1="{Binding ElementName=TestText, Path=ActualWidth}" 
      Y1="{Binding ElementName=TestText, Path=ActualHeight}" 
      X2="{Binding ElementName=TestText, Path=Canvas.Left}" 
      Y2="{Binding ElementName=TestText, Path=Canvas.Top}" 
      Stroke="Red" StrokeThickness="2" /> 
</Canvas> 
+0

Gracias, Rachel, por supuesto, esto haría el trabajo, pero la pregunta es más sobre ** extender decoraciones ** que dibujar una línea. –

+0

Personalmente, creo un UserControl personalizado que implementa este estilo y simplemente lo uso en lugar de un TextBlock o etiqueta cuando desea este comportamiento. Como alternativa, puede escribir una propiedad adjunta que haga lo mismo. – Rachel

+0

Esa es mi opinión de alguna manera: es fácil extender un control pero no un control Inline (en caso de que prefiera usarlo directamente en lugar de envolverlo dentro de InlineUIContainer). Además, algo así como dibujar una línea sobre el texto es más como una Decoración o Efecto. Ni siquiera puedes usar Adorners con un elemento en línea. –

1
<TextBlock> 
     <Run>this is normal Text</Run><LineBreak/> 
     <Run local:DiagonalStrikeThroughAdorner.StrikeThroughBrush="Red">Some text with diagonal decoration</Run><LineBreak/> 
     <Run>more normal text yeah</Run> 
    </TextBlock> 

la Adorner no se mostrará porque

var adornerLayer = AdornerLayer.GetAdornerLayer((Visual) parent); 
      if(adornerLayer == null) 

siempre devolverá un valor nulo, hay que establecer la propiedad adjunta después de la carrera se ha cargado.

Cuestiones relacionadas