使用#wpf获得流畅的动画?

时间:2020-05-01 12:10:18

标签: c# .net wpf animation canvas

我正在开发一个简单的图形查看器。我在画布上使用简单的椭圆和线条很好地渲染了它。

现在,我想在图形中导航一些点。您可以想象汽车在城市街道上穿行。

要使某些东西能够以一定的速度运行动画逻辑,我设置了DispatcherTimer并在那里执行了所有动画逻辑。它有效,但确实很断断续续。确实,我并不感到惊讶。我知道,使用事件系统在画布上进行渲染和进行动画处理的这种方式并不是您希望像2D游戏引擎那样流畅地运行的。

因此,我的问题是,成为WPF的新手,我是否可以做些改善性能/准确性的事情?我已经看到有一个可用于c#(SkiaSharp)的Skia软件包,我认为它可以提高渲染性能,但是以“准确”(此处没有实时os)帧速率运行逻辑又如何呢?

3 个答案:

答案 0 :(得分:1)

有必要使用Animatios以所需的方式显示数据。 WPF动画旨在用于平滑渲染,并在调度程序时表现出更好的性能。

在最简单的情况下,您将需要启动Double动画来更新视图模型的单个属性。然后根据此值重新计算不同对象的属性(大小,位置等)。

另一种可能的解决方案是定义自定义动画类。 WPF Tutorial - Part 2 : Writing a custom animation class中演示了此解决方案。此解决方案提供了更大的灵活性,但是通常您会获得一个可用于计算对象设置的相似值(可以将其视为“经过时间”)。

答案 1 :(得分:1)

性能不是WPF的主要设计目标之一。如果您需要WPF动画系统无法实现的高速自定义动画,那么最好直接从FrameworkElement派生并覆盖OnRender:

public class CustomControl : FrameworkElement
{
    public CustomControl()
    {
        // leave this line in to force a render of the control for each frame
        CompositionTarget.Rendering += (s, e) => InvalidateVisual();
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        var angle = Math.PI * DateTime.Now.Ticks / 10000000;
        var xoffset = 100 + (int)(50 * Math.Sin(angle));
        var yoffset = 100 + (int)(50 * Math.Cos(angle));
        drawingContext.DrawEllipse(Brushes.Red, null, new Point(xoffset, yoffset), 50, 50);
    }
}

答案 2 :(得分:0)

WPF中有一个专门针对您的情况的特殊机制-动画。我建议您阅读这篇文章:How to: Animate an Object Along a Path

下面是遍历简单图形的示例。还要注意,在示例中,我使用了一个预定义的路径(为简单起见)。在实践中,您可以从后台代码动态创建此类路径和动画。

<Canvas>
    <Canvas.Resources>
        <PathGeometry x:Key="AnimationPath" Figures="M 100,100 L 200,150 L 230,250 L 150,300 L 100,100"/>
    </Canvas.Resources>

    <Line X1="115" X2="215" Y1="115" Y2="165" Stroke="Green" StrokeThickness="5"/>
    <Line X1="215" X2="245" Y1="165" Y2="265" Stroke="Green" StrokeThickness="5"/>
    <Line X1="245" X2="165" Y1="265" Y2="315" Stroke="Green" StrokeThickness="5"/>
    <Line X1="165" X2="115" Y1="315" Y2="115" Stroke="Green" StrokeThickness="5"/>

    <Ellipse Width="30" Height="30" Canvas.Left="100" Canvas.Top="100" Fill="Red"/>
    <Ellipse Width="30" Height="30" Canvas.Left="200" Canvas.Top="150" Fill="Red"/>
    <Ellipse Width="30" Height="30" Canvas.Left="230" Canvas.Top="250" Fill="Red"/>
    <Ellipse Width="30" Height="30" Canvas.Left="150" Canvas.Top="300" Fill="Red"/>

    <Ellipse x:Name="traveller" Width="30" Height="30" Fill="Blue">
        <Ellipse.RenderTransform>
            <TranslateTransform x:Name="transform"/>
        </Ellipse.RenderTransform>
    </Ellipse>

    <Canvas.Triggers>
        <EventTrigger RoutedEvent="Loaded">
            <BeginStoryboard>
                <Storyboard RepeatBehavior="Forever">
                    <DoubleAnimationUsingPath PathGeometry="{StaticResource AnimationPath}"
                                              Storyboard.TargetName="transform"
                                              Storyboard.TargetProperty="X"
                                              Source="X"
                                              Duration="0:0:10"/>

                    <DoubleAnimationUsingPath PathGeometry="{StaticResource AnimationPath}"
                                              Storyboard.TargetName="transform"
                                              Storyboard.TargetProperty="Y"
                                              Source="Y"
                                              Duration="0:0:10"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Canvas.Triggers>
</Canvas>
相关问题