4
votes

I looked for this particular thing, because I thought it's quite important and puzzling thing, but I didn't find anything on that matter. What I'm thinking about is time scaling in WPF and Silverlight animations.

Suppose that we have an DoubleAnimation that lasts 4s and animates a property from 0 to 100. It's autoreversed, or there's a complementing animation that reverses its effects, that's not important. Let's say that event triggering this animation is a simple MouseOver.

Here's the problem: I hover my cursor over an element. The property gets from 0 to 100 in 4s. I move my cursor away for 1s, property gets from 100 to 75, and then I hover back. Now the property gets form 75 to 100 in 4s. It's obvious to the user, that the animation runs 4 times slower. Is there any way to scale the time of an animation? If I would want this animation to run from 75 to 100 in 1s, how would I do that? I myself am thinking maybe of a Converter that would take four parameters (absolute beginning and end, actual beginning, and timespan for the whole interval) and then spit out the proper time. Is there any more elegant way?

I noticed that it's generally not a problem when animations are fast. Human does not really observe the difference in speed when the animation runs in 0.2s or 0.1s, and maybe all animations should be as fast as possible to not deteriorate the experience. But please treat this question theoretically (hence no code sample). I'm just curious if there is any proper way to scale the animation time.

If there is an answer to my question somewhere over the web, please just direct me there.

Paweł

P.S. Don't mind my english, I'm not a native speaker ;)

3

3 Answers

0
votes

I know is not an answer to your exact question, but one way to approach this would be to capture MouseEnter and MouseLeave, check the current animation state and pause or resume it:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="AnimationTest.MainPage"
    Width="640" Height="480">
    <UserControl.Resources>
        <Storyboard x:Name="Rotate" AutoReverse="True">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)" Storyboard.TargetName="textBlock">
                <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                <EasingDoubleKeyFrame KeyTime="0:0:4" Value="100"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBlock x:Name="textBlock" Margin="197,216,200,215" TextWrapping="Wrap" Text="My Funky Text" FontSize="32" RenderTransformOrigin="0.5,0.5" MouseEnter="textBlock_MouseEnter" MouseLeave="textBlock_MouseLeave">
            <TextBlock.RenderTransform>
                <CompositeTransform/>
            </TextBlock.RenderTransform>
        </TextBlock>
    </Grid>
</UserControl>

Code:

private void textBlock_MouseEnter(object sender, MouseEventArgs e)
{
    var state = Rotate.GetCurrentState();
    if (state == ClockState.Stopped || state == ClockState.Filling) { Rotate.Begin(); } else Rotate.Resume();
}

private void textBlock_MouseLeave(object sender, MouseEventArgs e)
{
    Rotate.Pause();
}
0
votes

I did some more research. It appears that the only good way to scale the animation time is by using MultiConverter, which takes in the boundary values (e.g. 0 and 100 from my previous example), the current value of the animated property, and the running time for the full animation (e.g. 4s in my example). Then it should calculate what percentage of the animation should be done (so if the current value is 75, and the full range is 0-100, then 25% of the animation is left), and the return value should be the aforementioned percantage of the original timespan (25% of 4s is 1s). Maybe that's not the most elegant way to accomplish the goal, but it seems that it should work.

0
votes

I had this same problem with getting animations to behave linearly in the fashion you describe. I could not find a solution using WPF triggers in XAML without having to write code-behind.

Then I started using the VisualStateManager instead of triggers (which is supported in WPF 4 and Silverlight). All the animations behaved perfectly like you would expect them to!

I would recommend Expression Blend 4 for using the VisualStateManager since it takes only a few seconds to configure an object's various states using the UI.