Динамическое изменение анимации вращения в WPF

Я использую DoubleAnimation для изменения свойства Angle объекта RotationTransform. Несколько раз в секунду мне нужно изменить скорость вращения в ответ на внешние данные, чтобы вращение ускорялось и / или замедлялось (плавно) с течением времени. В настоящее время я делаю это, используя DoubleAnimation, которая бесконечно повторяется от 0,0 до 360,0 с длительностью X, а затем несколько раз в секунду:

  • Получите новое значение из внешних данных
  • Измените скорость DoubleAnimation на это значение
  • Повторно примените DoubleAnimation к свойству Angle еще раз

Примечание: я обнаружил, что мне пришлось изменить свойства To и From в анимации на «текущий угол» и «текущий угол + 360» - к счастью для меня RotationTransform не имеет проблем с углами> 360 градусов - чтобы предотвратить начало вращения снова с нулевого угла.

Мой вопрос: разумно ли это? Это не так. Непрерывное применение новых DoubleAnimations к свойству Angle при преобразовании вращения кажется неправильным - вроде как я разрешаю WPF анимировать вращение, в то время как я сам анимирую скорость вращения.

Есть ли способ лучше?


person Bill    schedule 28.03.2009    source источник


Ответы (1)


На раскадровке есть настройка 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); }
    }
}

Я уверен, что вы сможете приспособиться к своему использованию.

person John    schedule 28.03.2009
comment
Это было бы очень признательно. - person Bill; 28.03.2009
comment
Спасибо, я смогу это использовать. Забавно, что нам нужно вызвать метод (SetSpeedRatio), что означает, что я не могу анимировать изменение соотношения скоростей с помощью другой анимации, все в Xaml и все такое; но это выглядит намного правильнее, чем постоянно применять новые анимации для получения эффекта. Спасибо. - person Bill; 28.03.2009
comment
Этот ответ оказался наиболее полезным в нашем случае, но есть одно важное отличие, из-за которого он не сработал. по крайней мере с WPF в WinRT. Метод SetSpeedRatio () ничего не сделал, поэтому мы изменили его на свойство SpeedRatio, и это помогло. - person Johan B; 13.12.2013