How can I hold a WPF storyboard animation for a second, before continuing?

Mark A. Donohoe picture Mark A. Donohoe · May 17, 2012 · Viewed 7.7k times · Source

We have a color animation that blends from red to white. Currently, this is a linear fade. We know we can play with the Storyboard class's BeginTime and such, but that simply delays the start of the entire animation. We've also looked at the ease-in/ease-out side of things, but they don't seem to work either.

Specifically, we'd like to hold a value of red for one second, then fade from red to white over the next. Can that be done in pure XAML? If not, can it be done in code-behind manually setting up a storyboard? ...or do we have to use two separate storyboards and play them in sequence?

Answer

LPL picture LPL · May 18, 2012

Several ways to do this.

with key frames:

<Storyboard>
    <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Background.Color">
        <DiscreteColorKeyFrame Value="Red" KeyTime="0:0:0" />
        <DiscreteColorKeyFrame Value="Red" KeyTime="0:0:1" />
        <LinearColorKeyFrame Value="White" KeyTime="0:0:2" />
    </ColorAnimationUsingKeyFrames>
</Storyboard>

with two animations in sequence:

<Storyboard>
    <ColorAnimation Storyboard.TargetProperty="Background.Color"
                    From="Red" To="Red" Duration="0:0:1" />
    <ColorAnimation Storyboard.TargetProperty="Background.Color"
                    To="White" BeginTime="0:0:1" Duration="0:0:1" />
</Storyboard>

with a custom easing function:

<Storyboard>
    <ColorAnimation Storyboard.TargetProperty="Background.Color"
                    From="Red" To="White" Duration="0:0:2">
        <ColorAnimation.EasingFunction>
            <local:CustomEasingFunction />
        </ColorAnimation.EasingFunction>
    </ColorAnimation>
</Storyboard>

In this case a function that shows the transition in the first half of duration and holds the value in the second half. Because the default EasingMode is EaseOut this function will then 'play' backwards.

public class CustomEasingFunction : EasingFunctionBase
{
    public CustomEasingFunction() : base()
    { }

    protected override double EaseInCore(double normalizedTime)
    {
        return (normalizedTime < 0.5)
            ? normalizedTime * 2
            : 1;
    }

    protected override Freezable CreateInstanceCore()
    {
        return new CustomEasingFunction();
    }
}