创建自定义FrameworkContentElement以在WPF中的文本上方添加对角线 [英] Create custom FrameworkContentElement to add diagonal line over text in WPF

查看:406
本文介绍了创建自定义FrameworkContentElement以在WPF中的文本上方添加对角线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有什么方法可以创建自定义的 FrameworkContentElement (或 Inline ),并在其上绘制对角线

Is there any way to create a custom FrameworkContentElement (or an Inline) that draws a diagonal line over its content?

类似于穿越式装饰,但具有对角线形状:

Something like Strike-through decoration but with a diagonal shape:

TextDecoration TextEffect (已密封)。

有什么想法吗?

推荐答案

更新

我尝试创建一个示例,最小可能。在更复杂的情况下,您将不得不扩展它。外观如下:

I tried to create an example as minimal as possible. In more complex scenarios you will have to extend this. Here is how it looks:

这是相应的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>

这就是后面的代码:

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

}

玩得开心!

原始消息

通常这很难。我设法在流文档中的特定元素上添加了修饰符,但是有很多要考虑的案例。例如:如果将Inline包裹起来,应该怎么办?更进一步:如果此流文档位于RichTextBox中,则其内部会继续重新排列运行(合并或分离它们),这几乎会使所有事情弄乱。您必须仔细进行设置。

this is generally quite hard. I have managed to attach an adorner to specific elements in flowdocuments but there are many cornercases to consider. for example: what's supposed to happen if that Inline is wrapped around? further: if this flowdocument sits in a richtextbox, its internals keep rearranging runs (joining or separating them) which pretty much messes up everything. you have to set things up carefully.

请详细说明此内联的目标位置。在FlowdocumentScrollviewer内部?还是TextBlock?还是Richtextbox?由于您必须将装饰器附加到管理的FrameworkElement上(您可能已经注意到,您不能直接将Adorner附加到FrameworkContentElement上),所以我们需要知道内联的位置。

Please elaborate more on where this inline is going to be at. Inside a FlowdocumentScrollviewer? Or a TextBlock? Or a Richtextbox? As you have to attach the adorner to the governing FrameworkElement (as you probably already noticed you can't attach an Adorner to a FrameworkContentElement directly) we need to know where the inline sits.

尽管如此,我将描述如何完成此操作的一般方法:创建一个附加属性以创建装饰器。附加属性设置在将要装饰的内联上。装饰器保留对内联的引用,并附加到管理的FrameworkElement上。订阅到该框架元素上的layoutupdated并在Adorner上执行InvalidateVisual。装饰器OnRender根据Inlines ContentStart 和ContentEnd GetCharacterRect 矩形。完成。

I will describe the general route for how to accomplish this though: create an attached property thats going to create the adorner. the attached property is set on the inline that's going to be adorned. the adorner keeps a reference to the inline and is attached to the governing FrameworkElement. subscibe to layoutupdated on that frameworkelement and do an InvalidateVisual on the Adorner. The adorners OnRender draws the line with coordinates depending on the Inlines ContentStart and ContentEnd GetCharacterRect rectangles. done.

这篇关于创建自定义FrameworkContentElement以在WPF中的文本上方添加对角线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆