更改已启动DoubleAnimationUsingPath的路径

时间:2014-08-23 11:48:34

标签: wpf pathgeometry doubleanimation

是否可以改变路径,例如动画已在进行中PathGeometry的{​​{1}}属性?如果是这样,怎么样?

我的一些代码:

XAML:

DoubleAnimationUsingPath

代码隐藏:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <Canvas x:Name="BackgroundCanvas"
                Background="Transparent"
                Grid.ColumnSpan="2">
            <Ellipse Fill="Black" Width="10" Height="10" x:Name="Circ">
                <Ellipse.RenderTransform>
                    <TranslateTransform X="-5" Y="-5" />
                </Ellipse.RenderTransform>
            </Ellipse>
        </Canvas>

        <Rectangle x:Name="LeftRect" Width="100" Height="100" Grid.Column="0" Fill="#80002EE2" />
        <Rectangle x:Name="RightRect" Width="100" Height="100" Grid.Column="1" Fill="#8000B70A" />
    </Grid>
</Window>

这应该在两个矩形的中心之间移动一个10x10的圆圈。我想更改动画,如果尚未完成并且private void Window_Loaded(object sender, RoutedEventArgs e) { Func<FrameworkElement, Point> centerOf = ele => ele.TransformToVisual(BackgroundCanvas).Transform(new Point(ele.Width/2, ele.Height/2)); Point start = centerOf(LeftRect); Point end = centerOf(RightRect); LineGeometry geom = new LineGeometry(start, end); var animation = new DoubleAnimationUsingPath { Duration = Duration.Automatic, PathGeometry = PathGeometry.CreateFromGeometry(geom) }; animation.Source = PathAnimationSource.X; Circ.BeginAnimation(Canvas.LeftProperty, animation); animation.Completed += delegate { Window_Loaded(null, null); }; animation.Source = PathAnimationSource.Y; Circ.BeginAnimation(Canvas.TopProperty, animation); } 触发,那么当窗口例如是动画时动画实际上在矩形的中心结束。调整大小。

1 个答案:

答案 0 :(得分:1)

这是我的尝试

我在画布上添加了一个形状,当您单击画布中的任何位置时,形状将朝向鼠标指针移动。您可以在画布中再次单击其他任何位置,并且形状将更改其路径以跟随新指针位置。

XAML

<Canvas x:Name="BackgroundCanvas"
        Background="Transparent"
        PreviewMouseDown="BackgroundCanvas_PreviewMouseDown">
    <Ellipse Fill="Black"
             Width="10"
             Height="10"
             x:Name="circ">
        <Ellipse.RenderTransform>
            <TranslateTransform X="-5"
                                Y="-5" />
        </Ellipse.RenderTransform>
    </Ellipse>
</Canvas>

BackgroundCanvas_PreviewMouseDown

private void BackgroundCanvas_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    double sx = (double)circ.GetValue(Canvas.LeftProperty);
    double sy = (double)circ.GetValue(Canvas.TopProperty);
    Point tp = e.GetPosition(BackgroundCanvas);

    if (double.IsNaN(sx))
        sx = 0;
    if (double.IsNaN(sy))
        sy = 0;

    LineGeometry geom = new LineGeometry(new Point(sx, sy), tp);

    Path p = new Path() { Data = geom, Stroke = Brushes.Black };
    BackgroundCanvas.Children.Add(p);

    var animation = new DoubleAnimationUsingPath
    {
        Duration = Duration.Automatic,
        PathGeometry = PathGeometry.CreateFromGeometry(geom)
    };

    animation.Source = PathAnimationSource.X;
    circ.BeginAnimation(Canvas.LeftProperty, animation);
    animation.Source = PathAnimationSource.Y;
    circ.BeginAnimation(Canvas.TopProperty, animation);
}

结果

result

我添加了显示结果的路径。试一试,看看它有多接近


修改

我还尝试平滑动画路径,使其看起来不像直线

    Point pp;
    private void BackgroundCanvas_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        double sx = (double)circ.GetValue(Canvas.LeftProperty);
        double sy = (double)circ.GetValue(Canvas.TopProperty);
        Point tp = e.GetPosition(BackgroundCanvas);

        if (double.IsNaN(sx))
            sx = 0;
        if (double.IsNaN(sy))
            sy = 0;
        Point sp = new Point(sx, sy);
        StreamGeometry geom = new StreamGeometry();
        using (StreamGeometryContext ctx = geom.Open())
        {
            ctx.BeginFigure(sp, false, false);
            ctx.BezierTo(pp, tp, tp, true, false);
        }
        geom.Freeze();

        pp = tp;

        Path p = new Path() { Data = geom, Stroke = Brushes.Black };
        BackgroundCanvas.Children.Add(p);

        var animation = new DoubleAnimationUsingPath
        {
            Duration = Duration.Automatic,
            PathGeometry = PathGeometry.CreateFromGeometry(geom)
        };

        animation.Source = PathAnimationSource.X;
        circ.BeginAnimation(Canvas.LeftProperty, animation);
        animation.Source = PathAnimationSource.Y;
        circ.BeginAnimation(Canvas.TopProperty, animation);
    }

结果

result

我希望这可以解决你的问题,修改正在运行的动画的路径(实际上没有修改但是从触发的点开始一个新的动画),具有平滑的混合外观


编辑2

我将我的方法与您的代码相结合,现在当窗口大小改变时,圆圈将沿着第二个矩形的新路径。

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        Func<FrameworkElement, Point> centerOf = ele => ele.TransformToVisual(BackgroundCanvas).Transform(new Point(ele.Width / 2, ele.Height / 2));
        Point start = centerOf(LeftRect);
        Point end = centerOf(RightRect);

        LineGeometry geom = new LineGeometry(start, end);
        pp = end;
        var animation = new DoubleAnimationUsingPath
        {
            Duration = TimeSpan.FromMilliseconds(totalDuration),
            PathGeometry = PathGeometry.CreateFromGeometry(geom)
        };

        animation.Source = PathAnimationSource.X;
        Circ.BeginAnimation(Canvas.LeftProperty, animation);

        animation.Completed += delegate { Window_Loaded(null, null); };

        animation.Source = PathAnimationSource.Y;
        Circ.BeginAnimation(Canvas.TopProperty, animation);
        startTime = DateTime.Now;
        started = true;
    }

    Point pp;
    DateTime startTime;
    double totalDuration = 5000;
    bool started;
    private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        if (!started)
            return;

        Func<FrameworkElement, Point> centerOf = ele => ele.TransformToVisual(BackgroundCanvas).Transform(new Point(ele.Width / 2, ele.Height / 2));
        double sx = (double)Circ.GetValue(Canvas.LeftProperty);
        double sy = (double)Circ.GetValue(Canvas.TopProperty);
        Point tp = centerOf(RightRect);

        double timeLeft = totalDuration - DateTime.Now.Subtract(startTime).TotalMilliseconds;

        if (timeLeft < 1) return;

        if (double.IsNaN(sx))
            sx = 0;
        if (double.IsNaN(sy))
            sy = 0;
        Point sp = new Point(sx, sy);
        StreamGeometry geom = new StreamGeometry();
        using (StreamGeometryContext ctx = geom.Open())
        {
            ctx.BeginFigure(sp, false, false);
            ctx.BezierTo(pp, pp, tp, true, false);
        }
        geom.Freeze();

        pp = tp;

        var animation = new DoubleAnimationUsingPath
        {
            Duration = TimeSpan.FromMilliseconds(timeLeft),
            PathGeometry = PathGeometry.CreateFromGeometry(geom)
        };

        animation.Source = PathAnimationSource.X;
        Circ.BeginAnimation(Canvas.LeftProperty, animation);

        animation.Completed += delegate { Window_Loaded(null, null); };

        animation.Source = PathAnimationSource.Y;
        Circ.BeginAnimation(Canvas.TopProperty, animation);
    }

看看这是否是你要找的。当前圈子将使用其当前位置和第二个矩形来创建它的路径。如果您希望在窗口调整大小时移动圆圈,那么我们可能需要实现故事板并使用搜索方法来实现相同的目标。