0
votes

I have created a fade in and out animation, triggered by property changes in the viewmodel. This is working fine when fading in and out the first time, but each time I repeat this only the fade out is displayed, meaning the control remains invisible until it flashes to opacity 1 and then fades out.

XAML:

<DataTemplate x:Key="MessageTemplate">
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding FadeInAnimationState}" Value="Active">
            <DataTrigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity">
                            <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                            <EasingDoubleKeyFrame KeyTime="0:0:0.25" Value="1"/>
                        </DoubleAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.EnterActions>
        </DataTrigger>
        <DataTrigger Binding="{Binding FadeOutAnimationState}" Value="Active">
            <DataTrigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity">
                            <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
                            <EasingDoubleKeyFrame KeyTime="0:0:1" Value="0"/>
                        </DoubleAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.EnterActions>
        </DataTrigger>
    </DataTemplate.Triggers>
    <StatusBarItem>
        ...
    </StatusBarItem>
</DataTemplate>
...
<ContentPresenter ContentTemplate="{StaticResource MessageTemplate}" Content="{Binding}"/>

The Viewmodel properties responsible for trigggering the animation:

private DisplayState _messageState;
private DisplayState MessageState
{
    get { return _messageState; }
    set
    {
        _messageState = value;
        if (value == DisplayState.Displayed)
        {
            FadeOutAnimationState = AnimationState.Inactive;
            FadeInAnimationState = AnimationState.Active;
        }
        else
        {
            FadeInAnimationState = AnimationState.Inactive;
            FadeOutAnimationState = AnimationState.Active;
        }
    }
}

public AnimationState FadeInAnimationState
{
    ... // getter and setter with NotfiyPropertyChanged
}

public AnimationState FadeOutAnimationState
{
    ... // getter and setter with NotfiyPropertyChanged
}

And the call (debug):

MessageState = DisplayState.Displayed;
await Task.Delay(duration);
MessageState = DisplayState.Hidden;
await Task.Delay(TimeSpan.FromSeconds(1));

What am I doing wong?

1

1 Answers

2
votes

You need to remove your storyboards after you are done with them. Something like:

 <DataTrigger.EnterActions>
   <RemoveStoryboard BeginStoryboardName="FadeIn" />
   <RemoveStoryboard BeginStoryboardName="FadeOut" />       
   <BeginStoryboard Name="FadeIn">           
       <Storyboard>
          ...
       </Storyboard>
   </BeginStoryboard>
 </DataTrigger.EnterActions>

(and same for FadeOut, give it a name)

Or, you can do it on the ExitActions:

 <DataTrigger.EnterActions>
   <BeginStoryboard Name="FadeIn">           
       <Storyboard>
          ...
       </Storyboard>
   </BeginStoryboard>
 </DataTrigger.EnterActions>
 <DataTrigger.ExitActions>
   <RemoveStoryboard BeginStoryboardName="FadeIn" />
 </DataTrigger.ExitActions>

Otherwise the last storyboard will keep "pushing" its last value so you won't see any changes