WPF 在屏幕上不可见时停止动画

WPF stop an animation when it's not visible on the screen

我正在使用 AvalonEdit 创建一个 ANSI 终端,该终端可以正确地对代码进行颜色编码并实现一些样式,例如下划线和反转(为此效果非常好,这不是完整的 VT100 类型的东西)。

在 AvalonEdit 中 DocumentColorizingTransformer 将 ANSI 颜色代码转换为彩色文本或样式文本。昨晚我正在努力实施 ANSI Blink。我在使用这部分代码时遇到了问题:

else if (color.AnsiColor is Blink)
{
    // The color animation of the pulse, use the opacity to simulate blinking
    var da = new DoubleAnimation
    {
        Duration = new Duration(TimeSpan.FromMilliseconds(500)),
        From = 0,
        To = 1,
        AutoReverse = true
        RepeatBehavior = RepeatBehavior.Forever
    };

    // Get the foreground
    var foreground = element.TextRunProperties.ForegroundBrush;

    // Clone the foreground so it's not frozen and we can run animations on it.
    var blinkForeground = foreground.Clone();

    // Set the new foreground.
    element.TextRunProperties.SetForegroundBrush(blinkForeground);

    // Blink Blink Blink Blink
    blinkForeground.BeginAnimation(SolidColorBrush.OpacityProperty, da);
}

显然我希望此文本在屏幕上永远闪烁,这就是我将 RepeatBehavior 设置为永远的原因。 但是,它会继续使用 CPU,即使它滚出屏幕的可见部分(它可能没有渲染,但动画似乎仍然是 运行).

我的问题:

当一段文本滚出可见视图时,如何停止动画(不必通过 AvalonEdit 框中的所有内容,这可能非常非常大且不可行做性能明智)。如果我可以在动画离开屏幕时停止动画,然后在 ColorizeLine(DocumentLine line) 触发时重新启动它,那将是理想的。使用 AvalonEdit 我知道什么时候通过 ColorizeLine 它是可见的,但我不一定知道那时候什么是不可见的。我考虑保留对所有双重动画的引用列表,但我仍然不知道它们何时在屏幕上可见。

关于我如何处理这个问题的任何其他想法或想法?

如果有任何动画,WPF 将以每秒 60 帧的速度呈现 运行。如果没有实际更改,渲染速度相对较快,但当应用程序应该处于空闲状态时,它仍然会导致明显的 CPU 使用。 AvalonEdit 的插入符是切换开关(使用计时器)而不是使用动画来避免渲染不必要的帧。


DocumentColorizingTransformer中,您可以使用this.CurrentContext.VisualLine访问正在处理的VisualLineVisualLine 有一个 IsDisposed 属性,一旦 AvalonEdit 丢弃该行(如果该行再次可见,将再次调用您的着色器),它将更改为 true

没有事件告诉您线路何时被处理。但是,如果您在列表中跟踪所有动画及其包含 VisualLine 的动画,则可以使用 TextView.VisualLinesChanged 事件扫描已处理的 VisualLine 并停止相应的动画。