You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF/XAML中如何从上次动画旋转结束角度开始新的旋转动画?

WPF Grid多次旋转动画实现方案

问题说明

从WinForms转WPF/XAML,需求是点击左右按钮,让Grid以动画形式每次旋转90°(左/右),同一按钮点击4次回到初始位置。当前问题:第一次左转(-90°)、右转(+90°)正常,后续点击无反应——视觉上元素看似在旋转状态,但底层角度会回到初始值,导致动画重复执行时没有变化。

核心疑问:

  • 动画旋转结束后,如何保留Grid的新角度?
  • 如何实现每次点击时角度±90°的增量式旋转?

解决方案

WPF中Storyboard动画运行时会临时覆盖依赖属性的值,默认FillBehavior="HoldEnd"只是让视觉保持,但底层依赖属性的基础值并未改变。要实现连续旋转,需做到两点:

  1. 动画完成后,将动画的最终值固化为RotateTransform的Angle基础值
  2. 每次启动动画时,以当前Angle值为起点,目标值为当前值±90°

具体实现步骤

  1. 给RotateTransform命名,方便后台代码直接访问角度值
  2. 修改Storyboard为动态目标值,不再固定目标为90/-90,而是通过后台代码设置动画的起始和结束值
  3. 在动画完成事件中固化角度,将动画结束后的角度赋值给RotateTransform的Angle属性,覆盖基础值
  4. 通过后台代码启动动画,替代XAML中的EventTrigger,动态修改动画参数

修改后的代码

XAML部分

<Window x:Name="RotoTest" 
        x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="rototest" Height="179.612" Width="198" UseLayoutRounding="True">
    <Window.Resources>
        <!-- 可复用的旋转动画模板,不固定目标值 -->
        <Storyboard x:Key="RotateStoryboard">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" 
                                           Storyboard.TargetName="GridRoto" 
                                           FillBehavior="HoldEnd"
                                           Completed="RotationCompleted">
                <EasingDoubleKeyFrame KeyTime="0:0:2">
                    <EasingDoubleKeyFrame.EasingFunction>
                        <BackEase EasingMode="EaseInOut" Amplitude="0.3"/>
                    </EasingDoubleKeyFrame.EasingFunction>
                </EasingDoubleKeyFrame>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>

    <StackPanel Margin="0,-1,0,0" Height="162" VerticalAlignment="Top">
        <Viewbox x:Name="ViewboxRoto" Height="100">
            <Grid x:Name="GridRoto" Height="100" Width="100" Background="#FFC72323" RenderTransformOrigin="0.5,0.5">
                <Grid.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <!-- 给RotateTransform命名,方便后台访问 -->
                        <RotateTransform x:Name="GridRotateTransform"/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Grid.RenderTransform>
                <TextBox x:Name="textBox" Height="22" TextWrapping="Wrap" Text="TextBox" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="22,42,26,36"/>
            </Grid>
        </Viewbox>

        <!-- 绑定点击事件到后台代码 -->
        <Button Content="RotoLEFT" x:Name="Btn_RotoLEFT" Click="Btn_RotoLEFT_Click"/>
        <Button Content="RotoRIGHT" x:Name="Btn_RotoRIGHT" Click="Btn_RotoRIGHT_Click"/>
    </StackPanel>
</Window>

后台代码(VB.NET)

Class MainWindow
    ' 获取旋转动画的关键帧
    Private ReadOnly Property RotateKeyFrame As EasingDoubleKeyFrame
        Get
            Dim storyboard = TryCast(Resources("RotateStoryboard"), Storyboard)
            Dim animation = TryCast(storyboard.Children(0), DoubleAnimationUsingKeyFrames)
            Return TryCast(animation.KeyFrames(0), EasingDoubleKeyFrame)
        End Get
    End Property

    Private Sub Btn_RotoLEFT_Click(sender As Object, e As RoutedEventArgs)
        ' 设置动画目标值为当前角度-90
        RotateKeyFrame.Value = GridRotateTransform.Angle - 90
        ' 启动动画
        TryCast(Resources("RotateStoryboard"), Storyboard).Begin()
    End Sub

    Private Sub Btn_RotoRIGHT_Click(sender As Object, e As RoutedEventArgs)
        ' 设置动画目标值为当前角度+90
        RotateKeyFrame.Value = GridRotateTransform.Angle + 90
        ' 启动动画
        TryCast(Resources("RotateStoryboard"), Storyboard).Begin()
    End Sub

    Private Sub RotationCompleted(sender As Object, e As EventArgs)
        ' 动画完成后,固化当前角度为基础值
        GridRotateTransform.Angle = RotateKeyFrame.Value
        ' 可选:提示旋转完成
        MessageBox.Show($"旋转完成,当前角度:{GridRotateTransform.Angle:F0}°")
    End Sub
End Class

关键说明

  • 固化角度:动画完成后将RotateKeyFrame.Value赋值给GridRotateTransform.Angle,更新依赖属性的基础值,确保下次动画以当前角度为起点
  • 动态目标值:每次点击按钮时根据当前角度计算目标值,实现增量式旋转
  • 复用Storyboard:只定义一个动画模板,通过后台修改目标值,避免重复定义多个Storyboard

内容的提问来源于stack exchange,提问作者Trobit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 07:32:20