views:

603

answers:

1

I'm making my own ControlTemplate for a standard Button in WPF. I want to change the background of my button when the user hovers over the button with the mouse, but also when the user presses the button (to yet another color). This seems like a common behavior, but I can't get it to work.

My template consists of a Border with an Image inside. It is the background color (a gradient really) of the Border that I want to animate. I have triggers in my template that activates animations (storyboards).

The MouseOver/Out works just fine. My problem occurs when I press the button. The Press animation runs as it should, and so does the Release animation. But after this the MouseOut will never run. The button gets stuck in the MouseOver state.

What am I doing wrong?

<ControlTemplate TargetType="{x:Type Button}">
    <ControlTemplate.Resources>
        <Storyboard x:Key="MouseOverAnimation">
            <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop1" Storyboard.TargetProperty="Color" To="#ffefefff" Duration="0:0:0.2" />
            <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop2" Storyboard.TargetProperty="Color" To="#ffc7c7ff" Duration="0:0:0.2" />
        </Storyboard>
        <Storyboard x:Key="MouseOutAnimation">
            <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop1" Storyboard.TargetProperty="Color" To="#ffeeeeee" Duration="0:0:0.2" />
            <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop2" Storyboard.TargetProperty="Color" To="#ffcccccc" Duration="0:0:0.2" />
        </Storyboard>
        <Storyboard x:Key="MouseDownAnimation">
            <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop1" Storyboard.TargetProperty="Color" To="#ffc7c7ff" Duration="0:0:0.1" />
            <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop2" Storyboard.TargetProperty="Color" To="#ff9a9aff" Duration="0:0:0.1" />
        </Storyboard>
        <Storyboard x:Key="MouseUpAnimation">
            <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop1" Storyboard.TargetProperty="Color" To="#ffefefff" Duration="0:0:0.1" />
            <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop2" Storyboard.TargetProperty="Color" To="#ffc7c7ff" Duration="0:0:0.1" />
        </Storyboard>
    </ControlTemplate.Resources>


    <Border x:Name="ButtonBorder" CornerRadius="0" BorderBrush="#55aaaaaa" BorderThickness="1" Width="23" Height="22">
        <Border.Background>
            <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                <GradientBrush.GradientStops>
                    <GradientStop x:Name="ButtonBorderGradientStop1" Color="#ffeeeeee" Offset="0.0" />
                    <GradientStop x:Name="ButtonBorderGradientStop2" Color="#ffcccccc" Offset="1.0" />
                </GradientBrush.GradientStops>
            </LinearGradientBrush>
        </Border.Background>
        <Image x:Name="ButtonIcon" Source="icons/searchicon_bw.png" Width="16" Height="16" />
    </Border>


    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Trigger.EnterActions>
                <BeginStoryboard Storyboard="{StaticResource MouseOverAnimation}" />
            </Trigger.EnterActions>
            <Trigger.ExitActions>
                <BeginStoryboard Storyboard="{StaticResource MouseOutAnimation}" />
            </Trigger.ExitActions>
        </Trigger>
        <Trigger Property="IsPressed" Value="True">
            <Trigger.EnterActions>
                <BeginStoryboard Storyboard="{StaticResource MouseDownAnimation}" />
            </Trigger.EnterActions>
            <Trigger.ExitActions>
                <BeginStoryboard Storyboard="{StaticResource MouseUpAnimation}" />
            </Trigger.ExitActions>
        </Trigger>
    </ControlTemplate.Triggers> 
</ControlTemplate>
A: 

Animations have a property called FillBehavior, the default value is HoldEnd.

After your MouseUp animation finishes, it holds the value preventing the mouse out animation from displaying properly. The mouse out animation actually does run, but is covered by the mouse up animation. If you flip the order of your triggers, putting IsPressed first, you can see that the IsMouseOver animation covers all the IsPressed animations.

You can set FillBehavior to Stop to make the animations stop covering the property when they are done.

In your case, setting FillBehavior to Stop on your MouseOutAnimation and MouseUpAnimation does the trick.

(In this example set on the storyboard so it applies to all the contained animations.)

<ControlTemplate.Resources> 
    <Storyboard x:Key="MouseOverAnimation" Storyboard.TargetProperty="Color"> 
        <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop1" To="#ffefefff" Duration="0:0:0.2" /> 
        <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop2" To="#ffc7c7ff" Duration="0:0:0.2" /> 
    </Storyboard> 
    <Storyboard x:Key="MouseOutAnimation" Storyboard.TargetProperty="Color"
                FillBehavior="Stop"> <!-- <=================== -->
        <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop1" To="#ffeeeeee" Duration="0:0:0.2" /> 
        <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop2" To="#ffcccccc" Duration="0:0:0.2" /> 
    </Storyboard> 
    <Storyboard x:Key="MouseDownAnimation" Storyboard.TargetProperty="Color"> 
        <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop1" To="#ffc7c7ff" Duration="0:0:0.1" /> 
        <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop2" To="#ff9a9aff" Duration="0:0:0.1" /> 
    </Storyboard> 
    <Storyboard x:Key="MouseUpAnimation" Storyboard.TargetProperty="Color"
                FillBehavior="Stop">  <!-- <=================== -->
        <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop1" To="#ffefefff" Duration="0:0:0.1" /> 
        <ColorAnimation Storyboard.TargetName="ButtonBorderGradientStop2" To="#ffc7c7ff" Duration="0:0:0.1" /> 
    </Storyboard> 
</ControlTemplate.Resources>

You can find more info on FillBehavior in the MSDN article Animation Overview under What Happens After an Animation Ends?.

omdsmr
That solved my problem. Very informative answer! Thank you very much omdsmr! :)
haagel