wpfxamlwpf-animation

Pause/Resume Storyboard not work


What I need to do:

  1. At the time of the event GotFocus, no event of MouseEnter and MouseLeave run.

  2. After the events LostFocus, MouseEnter and MouseLeave become active again.

Given the needs, I've written the following code, but the commands for Pause and Resume do not work.

<ControlTemplate x:Key="SpecialNumber" TargetType="{x:Type TextBox}">
    <Grid>
        <Image x:Name="SpecialBg" Style="{DynamicResource CallStatusSpecialBg}"/>
        <Image x:Name="SpecialIBeam" Style="{DynamicResource CallStatusSpecialIBeam}" Source="../image/I-beam-b.png"/>
        <TextBox x:Name="SpecialText" Style="{DynamicResource CallStatusSpecialNumberText}" Text="5555" />
    </Grid>
    <ControlTemplate.Resources>
        <Storyboard x:Key="Hide">
            <DoubleAnimation Storyboard.TargetName="SpecialBg" Storyboard.TargetProperty="Opacity" Duration="0:0:0.4" To="0" />
            <DoubleAnimation Storyboard.TargetName="SpecialIBeam" Storyboard.TargetProperty="Opacity" Duration="0:0:0.2" To="0" />
            <DoubleAnimation Storyboard.TargetName="SpecialText" Storyboard.TargetProperty="Opacity" Duration="0:0:0.2" To="0" />
        </Storyboard>
        <Storyboard x:Key="ShowHalf">
            <DoubleAnimation Storyboard.TargetName="SpecialBg" Storyboard.TargetProperty="Opacity" Duration="0:0:0.2" To="1" />
            <DoubleAnimation Storyboard.TargetName="SpecialIBeam" Storyboard.TargetProperty="Opacity" Duration="0:0:0.4" To="1" />
            <DoubleAnimation Storyboard.TargetName="SpecialText" Storyboard.TargetProperty="Opacity" Duration="0:0:0.2" To="0.01" />
        </Storyboard>
        <Storyboard x:Key="Show">
            <DoubleAnimation Storyboard.TargetName="SpecialBg" Storyboard.TargetProperty="Opacity" Duration="0:0:0.2" To="1" />
            <DoubleAnimation Storyboard.TargetName="SpecialIBeam" Storyboard.TargetProperty="Opacity" Duration="0:0:0.4" To="1" />
            <DoubleAnimation Storyboard.TargetName="SpecialText" Storyboard.TargetProperty="Opacity" Duration="0:0:0.2" To="1" />
        </Storyboard>
    </ControlTemplate.Resources>
    <ControlTemplate.Triggers>

        <EventTrigger SourceName="SpecialText" RoutedEvent="UIElement.MouseEnter" >
            <EventTrigger.Actions>
                <BeginStoryboard Storyboard="{StaticResource ShowHalf}" x:Name="SpecialTextMouseEnter"/>
            </EventTrigger.Actions>
        </EventTrigger>

        <EventTrigger SourceName="SpecialText" RoutedEvent="UIElement.MouseLeave" >
            <EventTrigger.Actions>
                <BeginStoryboard Storyboard="{StaticResource Hide}" x:Name="SpecialTextMouseLeave"/>
            </EventTrigger.Actions>
        </EventTrigger>

        <EventTrigger SourceName="SpecialText" RoutedEvent="UIElement.GotFocus" >
            <EventTrigger.Actions>
                <PauseStoryboard BeginStoryboardName="SpecialTextMouseLeave" />
                <PauseStoryboard BeginStoryboardName="SpecialTextMouseEnter" />
                <BeginStoryboard Storyboard="{StaticResource Show}" x:Name="SpecialTextGotFocus"/>
            </EventTrigger.Actions>
        </EventTrigger>

        <EventTrigger SourceName="SpecialText" RoutedEvent="UIElement.LostFocus" >
            <EventTrigger.Actions>
                <ResumeStoryboard BeginStoryboardName="SpecialTextMouseLeave" />
                <ResumeStoryboard BeginStoryboardName="SpecialTextMouseEnter" />
                <BeginStoryboard Storyboard="{StaticResource Hide}" x:Name="SpecialTextLostFocus"/>
            </EventTrigger.Actions>
        </EventTrigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

Solution

  • Instead of using the EventTriggers, you can use a simple Trigger with a couple of MultiTriggers that allow you to define a complex condition.

    I have a solution for you.

    First of all, set the default Opacity of your elements to 0, because this will be the correct initial state:

    <Image Opacity="0"/>
    <Image Opacity="0" />
    <TextBox Opacity="0" />
    

    Then, define the triggers that will do the job:

    <ControlTemplate.Triggers>
        <!-- This trigger will unconditionally show the elements,
        if the text box has keyboard focus,
        and hide them, if the text box is not focused -->
        <Trigger Property="IsKeyboardFocusWithin" Value="True">
            <Trigger.EnterActions>
                <BeginStoryboard Storyboard="{StaticResource Show}"/>
            </Trigger.EnterActions>
            <Trigger.ExitActions>
                <BeginStoryboard Storyboard="{StaticResource Hide}"/>
            </Trigger.ExitActions>
        </Trigger>
    
        <!-- This trigger will partly show the elements, if the mouse cursor
        is over the text box, but it is not focused. If it's focused, then
        the previous trigger has already done its job -->
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsMouseOver" Value="True" />
                <Condition Property="IsKeyboardFocusWithin" Value="False"/>
            </MultiTrigger.Conditions>
            <MultiTrigger.EnterActions>
                <BeginStoryboard Storyboard="{StaticResource ShowHalf}" x:Name="ShowHalfStoryboard" />                                
            </MultiTrigger.EnterActions>
            <MultiTrigger.ExitActions>
                <RemoveStoryboard BeginStoryboardName="ShowHalfStoryboard"/>
            </MultiTrigger.ExitActions>
        </MultiTrigger>
    
        <!-- This trigger will hide the elements, if the mouse cursor
        is outside the text box, and it is not focused. If it's focused, then
        the first trigger has already done its job. If it's not focused and
        the cursor is over the text box, then the previous trigger works. -->
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsMouseOver" Value="False" />
                <Condition Property="IsKeyboardFocusWithin" Value="False"/>
            </MultiTrigger.Conditions>
            <MultiTrigger.EnterActions>
                <BeginStoryboard Storyboard="{StaticResource Hide}" x:Name="HideStoryboard" />
            </MultiTrigger.EnterActions>
            <MultiTrigger.ExitActions>
                <RemoveStoryboard BeginStoryboardName="HideStoryboard"/>
            </MultiTrigger.ExitActions>
        </MultiTrigger>
    
    </ControlTemplate.Triggers>