在 WPF 中动态更改旋转动画

发布于 2024-07-15 20:34:09 字数 576 浏览 8 评论 0原文

我正在使用 DoubleAnimation 对 RotationTransform 的 Angle 属性进行动画处理。 每秒几次,我需要根据外部数据改变旋转速率,以便旋转随着时间的推移加速和/或减慢(平滑)。 我目前正在通过使用 DoubleAnimation 来实现此目的,该 DoubleAnimation 在持续时间为 X 的情况下从 0.0 到 360.0 永远重复,然后每秒重复几次:

  • 从外部数据中获取新值
  • 将 DoubleAnimation 上的速率修改为该值 将
  • DoubleAnimation 重新应用到角度注意

:我确实发现我必须将动画上的 To 和 From 属性更改为“当前角度”和“当前角度+360” - 对我来说幸运的是 RotationTransform 在角度 > 方面没有问题。 360 度 - 防止从零角度重新开始旋转。

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

有没有更好的办法?

I am using a DoubleAnimation to anamiate the Angle property of a RotationTransform. Several times per second, I need to change the rate of the rotation in response to external data so that the rotation speeds up and/or slows down (smoothly) over time. I am currently doing this by using a DoubleAnimation that repeats forever from 0.0 to 360.0 with duration X, then several times per second:

  • Grab a new value from external data
  • Modify the rate on the DoubleAnimation to that value
  • Re-Apply the DoubleAnimation to the Angle property again

Note: I did find that I had to change the To and From properties on the animation to "current angle" and "current angle+360" - lucky for me RotationTransform has no trouble with angles > 360 degrees - to prevent starting the rotation over again from zero angle.

My question is: Is this reasonable? It does not seem so. Continously applying new DoubleAnimations to the Angle property on a rotation transform seems wrong - sort of like I am letting WPF animate the rotation, while I am animating the rotation speed myself.

Is there a better way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

默嘫て 2024-07-22 20:34:09

故事板上有一个 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); }
    }
}

我相信您可以适应您的使用情况。

On the storyboard there is a SpeedRatio setting which is a multiplier to the duration. You cannot bind to this however as it is not a dependency property.

To get around this you can use the SetSpeedRatio function on the storyboard. Note this only works if the story board is started in code (other wise you get an error).

The code below is an full example of how you would raise event in an object to effect the speed of the animation of a spinning rectangle. The purpose of the textbox and data bindings are to update the background object. The button is just so the textbox looses focus and updates the object.

<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>

Then the C# code

{
    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); }
    }
}

I am sure you can adapt to your usage.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文