创建自定义FrameworkContentElement以在WPF中的文本上添加对角线

el_*_*yan 7 wpf inline effects decorator custom-controls

有没有办法创建一个在其内容上绘制对角线的自定义FrameworkContentElement(或Inline)?

像穿透装饰但具有对角线形状的东西: 透视和对角装饰的例子

它不可能是固有的(TextDecorationTextEffect它们是密封的).

任何的想法?

Mar*_*ter 6

更新:

我尝试尽可能少地创建一个示例.在更复杂的场景中,您必须扩展它.以下是它的外观:

在此输入图像描述

这是相应的xaml:

<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>
Run Code Online (Sandbox Code Playgroud)

这就是代码隐藏:

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

}
Run Code Online (Sandbox Code Playgroud)

玩得开心!

原始讯息:

这通常很难.我已经设法将一个装饰器附加到flowdocuments中的特定元素,但有许多角落要考虑.例如:如果Inline缠绕在一起会发生什么?进一步说:如果这个flowdocument位于richtextbox中,它的内部保持重新排列运行(连接或分离它们),这几乎弄乱了所有东西.你必须仔细设置.

请详细说明此内联的位置.在FlowdocumentScrollviewer中?还是一个TextBlock?还是Richtextbox?因为您必须将装饰器附加到管理FrameworkElement(因为您可能已经注意到您无法直接将装饰器附加到FrameworkContentElement),我们需要知道内联所在的位置.

我将描述如何实现这一目标的一般途径:创建一个附加属性,用于创建装饰器.附加属性设置在将要装饰的内联中.adorner保留对内联的引用,并附加到管理FrameworkElement.subscibe to layoutupdated on frameworkelement并在Adorner上执行InvalidateVisual.装饰者OnRender根据Inlines ContentStart和ContentEnd GetCharacterRect矩形绘制具有坐标的线.完成.