我可以分别为 WPF 贝塞尔曲线控制点的 X 坐标和 Y 坐标设置动画吗?

Can I animate the X- and Y- coordinates of a WPF Bezier curve control point separately?

我正在尝试在 WPF 中创建一个动画贝塞尔曲线,我打算通过平滑和缓慢地为端点和控制点设置动画来制作 "living"。我不希望任何点遵循明显可预测的路径,如简单的椭圆或圆。

我通过使用两种不同的 DoubleAnimations 在其他更简单的动画中取得了成功,例如分别制作 Canvas.Top 和 Canvas.Left 动画。

但是在贝塞尔曲线段中,控制点和终点作为 Point() 实例给出,我似乎无法弄清楚如何分别为这些 Point 实例的 X 和 Y 坐标设置动画。尽管(例如)BezierSegment.ControlPoint2 有一个 PropertyPath,但似乎没有那个点的 X 坐标。

我已经研究过通过继承 PointAnimationBase 来实现我自己的自定义点动画,但是很难浏览文档以了解它们是如何联系在一起的 - 而且那里的示例并不多。

从 PointAnimationBase 继承的自定义动画是否是正确的方法,我如何将它绑定到 BezierSegment 的控制点?或者我应该看一些完全不同的东西来达到效果?

自定义 PointAnimation 似乎是一种明智的方法。

以下 XAML 展示了标准 PointAnimation 如何为 QuadraticBezierSegment 的 Point1 属性 设置动画:

<Path Stroke="Black" StrokeThickness="3">
    <Path.Data>
        <PathGeometry>
            <PathGeometry.Figures>
                <PathFigure StartPoint="100,200">
                    <PathFigure.Segments>
                        <QuadraticBezierSegment Point2="200,200"/>
                    </PathFigure.Segments>
                </PathFigure>
            </PathGeometry.Figures>
        </PathGeometry>
    </Path.Data>
    <Path.Triggers>
        <EventTrigger RoutedEvent="Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <PointAnimation
                        Storyboard.TargetProperty="Data.Figures[0].Segments[0].Point1"
                        From="150,200" To="150,0" Duration="0:0:1"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Path.Triggers>
</Path>

自定义 PointAnimation 需要您实现 GetCurrentValueCore 方法和 return 表示动画当前值的 Point 实例,具体取决于 animationClock 参数提供的当前时间:

public class MyPointAnimation : PointAnimationBase
{
    protected override Point GetCurrentValueCore(
        Point defaultOriginValue, Point defaultDestinationValue,
        AnimationClock animationClock)
    {
        double x = ... // as function of animationClock
        double y = ... // as function of animationClock
        return new Point(x, y);
    }

    protected override Freezable CreateInstanceCore()
    {
        return new MyPointAnimation();
    }
}