Introduction

This article is about simplifying the process of defining animation for button mouse over, pressed, enabled and disabled animations. The process of defining triggers is quite complicated when you include all IsMouseOver, IsPressed and IsEnabled states. You will also need to work hard and define BeginStoryboard/StopStoryboard precisely to make your desired animation start. Some of these states are overlapping. For instance when the button is in IsPressed state, most likely it will be also in IsMouseOver state and what leads to improper animation to act. It is also quite annoying to define all these complex triggers every time for such a common problem.

Solution

I have defined a new control - AnimatableButton, which is inherited from a standard WPF Button. This new AnimatableButton listens to state changes of the button, looks for corresponding animation and runs it. All you need to do is to define Storyboards with predefined names - “NormalAnimation”, “MouseOverAnimation”, “PressedAnimation” or “DisabledAnimation”.  You may define them either in the resource dictionary of the button or template. Its all you need to do. That’s all from your side,  the rest of the things  AnimatableButton will do for you.

The logic of choosing which animation to run is inside the GetAnimationName method:

protected virtual string GetCurrentAnimationName()
{
    switch (State)
    {
        case ButtonState.Normal:
            return "NormalAnimation";
        case ButtonState.MouseOver:
            return "MouseOverAnimation";
        case ButtonState.Pressed:
            return "PressedAnimation";
        case ButtonState.Disabled:
            return "DisabledAnimation";
        default:
            return string.Empty;
    }
}

As you see, this method is virtual, which means that you may extend the AnimatableButton and override its functionality. It will allow you to run animations which is based on the states other that IsMouseOver, IsPressed and IsEnabled. You may also force the button to update its visual state by calling the InvalidateAnimation(). The last will run the animation based on GetAnimationName method.

The button also exposes its State. Its an enumeration which has values: Normal, MouseOver, Pressed and Disabled. You may use it at your own needs.

Usage Example

Below is an example of a button which has a template and animations defined. Please notice that there are no triggers defined.

<common:AnimatableButton >
  <common:AnimatableButton.Style>
    <Style TargetType="{x:Type common:AnimatableButton}">
      <Style.Setters>
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate TargetType="{x:Type common:AnimatableButton}">
              <Border>
                <Border.Background>
                  <SolidColorBrush x:Name="bg" />
                </Border.Background>
                <ContentPresenter />
              </Border>
              <ControlTemplate.Resources>
                <Storyboard x:Key="NormalAnimation">
                  <ColorAnimation To="Yellow" Duration="00.200" 
                   Storyboard.TargetName="bg" 
                   Storyboard.TargetProperty="Color" />
                </Storyboard>
                <Storyboard x:Key="MouseOverAnimation">
                  <ColorAnimation To="Red" Duration="00.200" 
                   Storyboard.TargetName="bg" 
                   Storyboard.TargetProperty="Color" />
                </Storyboard>
                <Storyboard x:Key="PressedAnimation">
                  <ColorAnimation To="Blue" Duration="00.200" 
                   Storyboard.TargetName="bg" 
                   Storyboard.TargetProperty="Color" />
                </Storyboard>
                <Storyboard x:Key="DisabledAnimation">
                  <ColorAnimation To="DarkGray" Duration="00.200" 
                   Storyboard.TargetName="bg" 
                   Storyboard.TargetProperty="Color" />
                </Storyboard>
              </ControlTemplate.Resources>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style.Setters>
    </Style>
  </common:AnimatableButton.Style>
</common:AnimatableButton>

Downloads