Home » c# » c# – Storyboard animation on an element within a TabItem does not stop when changing tabs

c# – Storyboard animation on an element within a TabItem does not stop when changing tabs

Posted by: admin February 21, 2020 Leave a comment

Questions:

I have a TabControl with a Border element that I need to animate (make the border flash Yellow to orange) when a property on a viewmodel is greater than zero, via Data Binding, but remain black if the value is zero. Each TabItem has it’s own instance of the viewmodel, so the property value could be different for each TabItem, therefore the animation should only be activated on the appropriate TabItem.

I have several similar elements, so I am using a MultiDataTrigger to check for a tag on the element, as well as check the property value (via a converter).

I can successfully animate the BorderBrush when selecting a TabItem where the property value is greater than zero, but when I then select a TabItem where the property value is equal to zero, the animation should stop, but does not. I am also changing the BorderThickness and the Margin, and these settings return to the normal settings as expected, but the animation does not stop.

I am using a Style.Trigger to apply the animation, and a converter to convert the property’s value from an int to a boolean (true if greater than zero, and false if zero).

Here is my xaml code (from app.xaml):

    <Style TargetType="{x:Type Border}" x:Key="JobFilterExternalBorder">
        <Setter Property="BorderThickness" Value="3"/>
        <Setter Property="BorderBrush" Value="Black"/>
        <Setter Property="CornerRadius" Value="3"/>
        <Setter Property="Margin" Value="2,0,1,0.8"/>
        <Style.Triggers>
            <!-- Add Data Trigger to identify if filter is UnprocessedParts and value is > 0, and animate border to imitate a flashing border -->
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Tag}" Value="IsUnprocessed"/>
                    <Condition Binding="{Binding UnprocessedQty, Converter={StaticResource ConvertNonZeroToBoolean}}" Value="true"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="BorderThickness" Value="6"/>
                    <Setter Property="Margin" Value="0,-2,-1,-1.2"/>
                </MultiDataTrigger.Setters>
                <MultiDataTrigger.EnterActions>
                    <BeginStoryboard Name="FlashStoryboard" Storyboard="{StaticResource AnimationFlashYellowToOrange}">
                    </BeginStoryboard>
                </MultiDataTrigger.EnterActions>
                <MultiDataTrigger.ExitActions>
                    <StopStoryboard BeginStoryboardName="FlashStoryBoard" />
                    <RemoveStoryboard BeginStoryboardName="FlashStoryBoard"/>
                </MultiDataTrigger.ExitActions>
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>

And my Storyboard:

    <Storyboard x:Key="AnimationFlashYellowToOrange" Storyboard.TargetProperty="BorderBrush" RepeatBehavior="Forever" Duration="0:0:1" FillBehavior="Stop">
        <ObjectAnimationUsingKeyFrames>
            <DiscreteObjectKeyFrame KeyTime="0:0:0">
                <DiscreteObjectKeyFrame.Value>
                    <SolidColorBrush Color="Yellow" />
                </DiscreteObjectKeyFrame.Value>
            </DiscreteObjectKeyFrame>
            <DiscreteObjectKeyFrame KeyTime="0:0:0.5">
                <DiscreteObjectKeyFrame.Value>
                    <SolidColorBrush Color="Orange" />
                </DiscreteObjectKeyFrame.Value>
            </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>

And the view to which this is being applied:

    <Border Name="UnprocessedQtyBorder" Tag="IsUnprocessed" Style="{StaticResource JobFilterExternalBorder}" >
    </Border>

I can confirm that the MultiDataTrigger is working fine because the BorderThickness and changes back to the normal thickness when the MultiDataTrigger becomes false when selecting a TabItem where the property value is equal to zero. It’s just the animation that does not stop.

I have tried:

  • Adding StopStoryboard to the MultiDataTrigger.ExitActions
  • Adding RemoveStoryboard to the MultiDataTrigger.ExitActions
  • Including FillBehaviour="Stop"
  • Adding a second MultiDataTrigger to start a new Storyboard that sets the BorderBrush to black
  • Changing the order of the Style settings to have the MultiDataTrigger before the standard property settings
  • Searching the internet for any other examples that might point me in the right direction

I need to have the Storyboard animate the border continuously while the offending element is on screen, so I have included the RepeatBehavior="Forever" property

I am following MVVM design pattern and would prefer to avoid having code-behind, but I’m not zealous about it.

I have been struggling with this all day and have not made any progress, so this is my last hope.

EDIT:
I suspect the MultiDataTrigger.ExitActions are never executed in order to stop the Storyboard, so an additional question must be asked; Is it even possible to stop a Storyboard in this manner? Can the MultiDataTrigger.ExitActions be triggered to execute some other way?

How to&Answers: