There is a picture (download indicator). The picture implies a rotation at a certain number of degrees per clock (not smooth). How can I do that? Normal DoubleAnimation rotates smoothly.

 <Image VerticalAlignment="Center" HorizontalAlignment="Center" Source="{StaticResource LoadingImage}" Stretch="None" RenderTransformOrigin="0.5,0.5"> <Image.RenderTransform> <RotateTransform x:Name="rotate"/> </Image.RenderTransform> <Image.Triggers> <EventTrigger RoutedEvent="Loaded"> <BeginStoryboard> <Storyboard> <DoubleAnimation By="45" To="360" Storyboard.TargetName="rotate" Storyboard.TargetProperty="Angle" Duration="0:0:2" RepeatBehavior="Forever"> </DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger> </Image.Triggers> </Image> 

UPD

By "not smooth" I mean instant. That is, I need the picture to rotate in a circle continuously at 45 degrees per clock. Tact should be instantaneous. That is, it was 0 degrees, it became immediately 45. After some time (for example, 0.2 seconds), another +45 and so on ...

  • 2
    Post a non-working code in question that could be fixed. Respect colleagues. - anme
  • @anme hold. Simply, this code most likely has little to do with the solution and someone just has it ready. Therefore, I did not consider it necessary to post it right away - iRumba
  • Look at DoubleAnimationUsingKeyframes . I will write later if no one has time to me. - VladD
  • @VladD, I probably didn’t figure it out well, but if I understand correctly, I’ll have to write each frame separately to DoubleAnimationUsingKeyframes to solve my problem. Or not? - iRumba
  • @iRumba: Hmm, well, yes, I have to prescribe all the frames. How else? KeyFrame value can be any according to the idea. Well, or you need to think not through KeyFrame , yes. - VladD

3 answers 3

You need a uniform animation, but in steps. This is a non-standard animation, so let's turn to the Sacred Source of Knowledge . It is advised to create your own KeyFrame . This will do.

We inherit from DoubleKeyFrame , since we are animating a property of type double . We need a property that stores the number of parts, we put it in the standard DependencyProperty NumberOfParts . We also need to implement abstract methods CreateInstanceCore (which simply clones our object, for it we will put a protected constructor), and most importantly - the InterpolateValueCore method, which will be our logic for calculating the value.

 class StepwiseDoubleKeyFrame : DoubleKeyFrame { public StepwiseDoubleKeyFrame() { } protected StepwiseDoubleKeyFrame(double value, KeyTime keyTime, int numberOfParts) : base(value, keyTime) { NumberOfParts = numberOfParts; } protected override Freezable CreateInstanceCore() => new StepwiseDoubleKeyFrame(Value, KeyTime, NumberOfParts); protected override double InterpolateValueCore(double baseValue, double keyFrameProgress) { var fullDiff = Value - baseValue; // полный путь, который нужно пройти за целый фрейм // в keyFrameProgress текущее время фрейма, от 0 до 1. // считаем, в какую из частей мы сейчас попадаем. // например, если у нас 6 частей, а время между 4/6 и 5/6, по показываем 4/6 var currentPart = Math.Floor(keyFrameProgress * NumberOfParts) / NumberOfParts; return baseValue + currentPart * fullDiff; } public int NumberOfParts { get { return (int)GetValue(NumberOfPartsProperty); } set { SetValue(NumberOfPartsProperty, value); } } public static readonly DependencyProperty NumberOfPartsProperty = DependencyProperty.Register( "NumberOfParts", typeof(int), typeof(StepwiseDoubleKeyFrame), new PropertyMetadata(4)); // по умолчанию 4 части } 

Now our XAML looks like this:

 <Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="..." RenderTransformOrigin="0.5,0.5" Width="75"> <Image.RenderTransform> <RotateTransform x:Name="Rotation"/> </Image.RenderTransform> <Image.Triggers> <EventTrigger RoutedEvent="Loaded"> <BeginStoryboard> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Rotation" Storyboard.TargetProperty="Angle" Duration="0:0:1" RepeatBehavior="Forever"> <local:StepwiseDoubleKeyFrame KeyTime="100%" Value="360" NumberOfParts="8"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Image.Triggers> </Image> 

Result:

twist-twirl, I want to show progress

  • Almost perfect. Almost, because there still need to trim the number of frames per second. After all, as I understand it, InterpolateValueCore will be executed 60 times per second. Since smooth animation is not needed here, these are extra resources. Although it is offhand. Not yet added to the project. - iRumba
  • @iRumba: Well, since the resulting value of the angle will be the same, I think that there should be no big expenses. Well this is only a calculation, not a rotation of the picture. - VladD
  • Big will not. but in my case this animation will spin at the time of the database query. The database is local SQLite, that is, the query will not be executed on a separate server or even in another process. Probably, I sat out with the old iron, but I try to avoid such unnecessary expenses when it does not cause inconvenience, of course. - iRumba
  • @iRumba: And you try to turn off the visibility of the animated element. In this picture, of course, will not be updated. A 60 changes double 'and per second against the background of reading from the base - zero. - VladD

At the moment, decided in this way

 <Storyboard Timeline.DesiredFrameRate="8"> <DoubleAnimation By="45" To="360" IsAdditive="True" Storyboard.TargetName="rotate" Storyboard.TargetProperty="Angle" Duration="0:0:1" RepeatBehavior="Forever"> </DoubleAnimation> </Storyboard> 

Timeline.DesiredFrameRate="8" means 8 frames per second. The animation works for 1 second and during this time rotates 8 times (from 0 to 360 by 45 degrees at a time).

I don’t really like this solution, but I haven’t found it better yet.

    Add an Easing function to your animation.

     <DoubleAnimation By="45" To="360" Storyboard.TargetName="rotate" Storyboard.TargetProperty="Angle" Duration="0:0:2" RepeatBehavior="Forever"> <DoubleAnimation.EasingFunction> <CircleEase EasingMode="EaseIn" /> </DoubleAnimation.EasingFunction> </DoubleAnimation> 
    • And what is it? Just the speed increases. - iRumba
    • I updated the question ... added clarification. You did not understand what I meant. - iRumba