首页 文章

在WPF中动态更改旋转动画

提问于
浏览
9

我正在使用DoubleAnimation来动画RotationTransform的Angle属性 . 每秒几次,我需要根据外部数据改变旋转速率,以便随着时间的推移旋转速度加快和/或减慢(平滑) . 我目前正在通过使用DoubleAnimation来实现这一点,DoubleAnimation从持续时间为X,然后每秒数次,从0.0到360.0永久重复:

  • 从外部数据中获取新值

  • 将DoubleAnimation的速率修改为该值

  • 再次将DoubleAnimation重新应用于Angle属性

注意:我确实发现我必须将动画上的To和From属性更改为“当前角度”和“当前角度360” - 幸运的是RotationTransform在角度> 360度时没有问题 - 以防止再次开始旋转从零角度 .

我的问题是:这合理吗?它似乎并非如此 . 在旋转变换上不断将新的DoubleAnimations应用于Angle属性似乎是错误的 - 有点像我让WPF为旋转设置动画,而我自己动画旋转速度 .

有没有更好的办法?

1 回答

  • 8

    在故事板上有一个SpeedRatio设置,它是持续时间的乘数 . 但是,您无法绑定到此,因为它不是依赖项属性 .

    要解决此问题,您可以在故事板上使用SetSpeedRatio功能 . 请注意,这仅在故事板以代码启动时才有效(否则您会收到错误) .

    下面的代码是一个完整的示例,说明如何在对象中引发事件以影响旋转矩形的动画速度 . 文本框和数据绑定的目的是更新背景对象 . 按钮只是文本框失去焦点并更新对象 .

    <Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <StackPanel>
          <Rectangle Margin="50" Width="50" Height="50" Fill="Red" x:Name="rc">
            <Rectangle.RenderTransform>
              <RotateTransform x:Name="TransRotate"
                               CenterX="25" CenterY="25" Angle="0" />
            </Rectangle.RenderTransform>
            <Rectangle.Resources>
              <Storyboard x:Key="spin">
                <DoubleAnimation x:Name="da" 
                                 Storyboard.TargetName="TransRotate" 
                                 Storyboard.TargetProperty="Angle"
                                 By="360" 
                                 Duration="0:0:10"  
                                 AutoReverse="False" 
                                 RepeatBehavior="Forever" />
              </Storyboard>
            </Rectangle.Resources>
          </Rectangle>
          <TextBox Text="{Binding Speed}" />
          <Button>Update Speed</Button>
        </StackPanel>
    </Window>
    

    然后是C#代码

    {
        public Window1()
        {
            InitializeComponent();
    
            //create new  object
            BackgroundObject bo = new BackgroundObject();
    
            //binding only needed for the text box to change speed value
            this.DataContext = bo;
    
            //Hook up event
            bo.SpeedChanged += bo_SpeedChanged;
    
            //Needed to prevent an error
            Storyboard sb = (Storyboard)rc.FindResource("spin");
            sb.Begin(); 
        }
    
        //Change Speed
        public void bo_SpeedChanged(  object sender, int newSpeed)
        {
            Storyboard sb = (Storyboard)rc.FindResource("spin");
            sb.SetSpeedRatio(newSpeed);
        }
    }
    
    public delegate void SpeedChangedEventHandler(object sender, int newSpeed);
    
    public class BackgroundObject
    {
        public BackgroundObject()
        {
            _speed = 10;
        }
    
        public event SpeedChangedEventHandler SpeedChanged;
    
        private int _speed;
        public int Speed
        { 
            get { return _speed; }
            set { _speed = value; SpeedChanged(this,value); }
        }
    }
    

    我相信你可以适应你的用法 .

相关问题