WPF – Advanced Animation Effects

Standard

When designing an application there are many reasons to use an Animation Effect to an element in order to draw attention to it. My specific implementation was for monitoring application but the effects can be leveraged in many scenarios. Here are 5 common variations of requested animation effects.

GIF Example of Output

The XAML

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" x:Class="MainWindow"
    Title="MainWindow" Height="450" Width="250">
    <Window.Resources>

        <!-- Marching Ants -->
        <Storyboard x:Key="MarchingAnts">
                <DoubleAnimation BeginTime="00:00:00"
                                Storyboard.TargetName="AlertBox"
                                Storyboard.TargetProperty="StrokeThickness"
                                To="4"
                                Duration="0:0:0.25" />
                           <!-- If you want to run counter-clockwise, just swap the 'From' and 'To' values. -->
                <DoubleAnimation BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="AlertBox" Storyboard.TargetProperty="StrokeDashOffset" 
                                Duration="0:3:0" From="1000" To="0"/>
        </Storyboard>

        <!-- Pulse -->
        <Storyboard x:Key="Pulse" RepeatBehavior="Forever">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="PulseBox">
                <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1.15"/>
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="PulseBox">
                <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1.15"/>
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>

        <!-- Flipper -->
        <Storyboard x:Key="Flipper" RepeatBehavior="Forever">
            <PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)" Storyboard.TargetName="FlipperBox">
                <EasingPointKeyFrame KeyTime="0:0:1" Value="0.5,0.5"/>
                <EasingPointKeyFrame KeyTime="0:0:2" Value="0.5,0.5"/>
            </PointAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="FlipperBox">
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="-1"/>
                <EasingDoubleKeyFrame KeyTime="0:0:2" Value="1"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>


        <!-- Elasic Lines -->
        <Storyboard x:Key="ElasticLines" RepeatBehavior="Forever" AutoReverse="True">
            <PointAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(LinearGradientBrush.EndPoint)" Storyboard.TargetName="ElasticBox">
                <EasingPointKeyFrame KeyTime="0:0:4" Value="12,8"/>
            </PointAnimationUsingKeyFrames>
        </Storyboard>

        <!-- Knight Rider -->
        <Storyboard x:Key="KnightRider" RepeatBehavior="Forever" AutoReverse="True">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="KRBox">
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="-50"/>
                <EasingDoubleKeyFrame KeyTime="0:0:2" Value="50"/>
                <EasingDoubleKeyFrame KeyTime="0:0:3" Value="0"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>

    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded">
            <BeginStoryboard Storyboard="{StaticResource Pulse}"/>
            <BeginStoryboard Storyboard="{StaticResource MarchingAnts}"/>
            <BeginStoryboard Storyboard="{StaticResource Flipper}"/>
            <BeginStoryboard Storyboard="{StaticResource ElasticLines}"/>
            <BeginStoryboard Storyboard="{StaticResource KnightRider}"/>
        </EventTrigger>
    </Window.Triggers>

    <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
        <Grid.Resources>
            <Style TargetType="{x:Type TextBlock}">
                <Setter Property="Foreground" Value="White"/>
                <Setter Property="FontWeight" Value="Bold"/>
                <Setter Property="FontSize" Value="35"/>
                <Setter Property="HorizontalAlignment" Value="Center"/>
                <Setter Property="VerticalAlignment" Value="Center"/>
                <Setter Property="Text" Value="ALERT"/>
            </Style>
            <Style TargetType="{x:Type Grid}">
                <Setter Property="Margin" Value="0,10"/>                
            </Style>
            <Style TargetType="{x:Type Rectangle}">
                <Setter Property="Height" Value="50"/>
                <Setter Property="Width" Value="150"/>
            </Style>
        </Grid.Resources>

        <StackPanel>

        <!-- Marching Ants -->
        <Grid>

            <Rectangle x:Name="AlertBox"
                      Stroke="Red" 
                       StrokeDashOffset="2" StrokeDashArray="5" Margin="5">
                <Rectangle.Fill>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="6,4" MappingMode="Absolute" SpreadMethod="Repeat">
                        <GradientStop Color="Red" Offset="0.25"/>
                        <GradientStop Color="#00000000" Offset="0.15"/>
                    </LinearGradientBrush>
                </Rectangle.Fill>
            </Rectangle>

            <TextBlock/>

        </Grid>
        <!-- End Marching Ants -->


        <!-- Pulse : Will not skew other elements location like width/height animations would. -->
        <Grid>
            <Border x:Name="PulseBox"
                        Background="Red" RenderTransformOrigin="0.5,0.5">
                <Border.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <RotateTransform/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Border.RenderTransform>

                <TextBlock/>

            </Border>
        </Grid>
        <!-- End Pulse -->


        <!-- Flipper -->
        <Grid>
            <Border x:Name="FlipperBox"
                        Background="Red">
                <Border.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <RotateTransform/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Border.RenderTransform>

                <TextBlock/>

            </Border>
        </Grid>
        <!-- End Flipper -->


        <!-- Elastic Lines -->
        <Grid>
            <Rectangle x:Name="ElasticBox"
                      Stroke="Red" StrokeThickness="5" Margin="5">
                <Rectangle.Fill>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="6,4" MappingMode="Absolute" SpreadMethod="Repeat">
                        <GradientStop Color="Red" Offset="0.25"/>
                        <GradientStop Color="#00000000" Offset="0.15"/>
                    </LinearGradientBrush>
                </Rectangle.Fill>
            </Rectangle>

            <TextBlock/>

        </Grid>
        <!-- End Elastic Box -->


        <!-- Knight Rider -->
        <Grid>
            <Rectangle Fill="Red"/>
            <Rectangle x:Name="KRBox" Width="50" Fill="White" RenderTransformOrigin="0.5,0.5">
                <Rectangle.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <RotateTransform/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Rectangle.RenderTransform>
            </Rectangle>

            <TextBlock Foreground="Red"/>

        </Grid>
        <!-- End Knight Rider -->

        </StackPanel>

    </Grid>
</Window>

Hopefully this helps you with your animation needs!

Leave a Reply

Your email address will not be published. Required fields are marked *