Introduction
This article is about simplifying the process of defining button mouse over, pressed, enabled, and disabled animations. The process of defining triggers is quite complicated when you include all of the 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 the IsPressed
state, most likely, it will be also in the IsMouseOver state and that leads to an 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 the standard WPF Button
. This new AnimatableButton
listens to state changes of the button, looks for the 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 the template. That is all you need to do. AnimatableButton
will do the rest for you.
The logic for 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 AnimatableButton
and override its functionality. It will allow you to run animations based on the states other than IsMouseOver
, IsPressed
, and IsEnabled
. You may also force the button to update its visual state by calling InvalidateAnimation()
. The last one will run the animation based on the GetAnimationName
method.
The button also exposes its State
. Its an enumeration which has the values: Normal
, MouseOver
, Pressed
, and Disabled
. You may use it for 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="0:0:0.200"
Storyboard.TargetName="bg"
Storyboard.TargetProperty="Color" />
</Storyboard>
<Storyboard x:Key="MouseOverAnimation">
<ColorAnimation To="Red" Duration="0:0:0.200"
Storyboard.TargetName="bg"
Storyboard.TargetProperty="Color" />
</Storyboard>
<Storyboard x:Key="PressedAnimation">
<ColorAnimation To="Blue" Duration="0:0:0.200"
Storyboard.TargetName="bg"
Storyboard.TargetProperty="Color" />
</Storyboard>
<Storyboard x:Key="DisabledAnimation">
<ColorAnimation To="DarkGray" Duration="0:0:0.200"
Storyboard.TargetName="bg"
Storyboard.TargetProperty="Color" />
</Storyboard>
</ControlTemplate.Resources>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</common:AnimatableButton.Style>
</common:AnimatableButton>
Origin
The origin of this article can be found at WPF Animatable Button.